李沐pytorch学习-经典CNN的原理及代码实现

一、LeNet

1.1 模型结构

        LeNet结构如图1所示,汇聚层即池化层,这里池化Stride(步幅)与池化层长宽一致,因此使得池化后大小减半。

图1. LeNet结构

1.2 代码实现

       代码实现如下:

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Flatten(),
    nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    nn.Linear(120, 84), nn.Sigmoid(),
    nn.Linear(84, 10))
        nn.Sequential 即表示把括号里的层按序排起来,代码与每层的对应关系如图2所示。
图2. 代码与LeNet结构中每层的对应关系
        nn.Flatten() 作用是将16@5×5的汇聚层展平程1维向量,作为全连接层的输入,因此不对应图中的某层。
        nn.Conv2d(1, 6, kernel_size=5, padding=2) 为卷积层,表示输入的通道数为1,输出的通道数为6,直观表达是经过该层后数据变“厚”了,卷积核大小为5×5,上下左右均填充2行(填充0)。nn.Sigmoid()表示该层的激活函数为Sigmoid。
        nn.AvgPool2d(kernel_size=2, stride=2) 表示平均池化,池化层大小为2×2,步幅为2。
        nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid() 为卷积层,四周无填充,激活函数为Sigmoid。
        nn.AvgPool2d(kernel_size=2, stride=2) 为平均池化层。
        nn.Linear(16 * 5 * 5, 120), nn.Sigmoid() 为线性全连接层,输入层神经元数为16×5×5,输出层神经元数为120,无隐含层,激活函数为Sigmoid。
        nn.Linear(120, 84), nn.Sigmoid() 为线性全连接层,输入层神经元数为120,输出层神经元数为84,无隐含层,激活函数为Sigmoid。
        nn.Linear(84, 10) 为线性全连接层,输入层神经元数为84,输出层神经元数为10,无隐含层,无激活函数。

1.3 检查模型

        查看输出层的名及Size。

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Flatten(),
    nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    nn.Linear(120, 84), nn.Sigmoid(),
    nn.Linear(84, 10))

X = torch.rand(size=(1, 1, 28, 28), dtype=torch.float32)
for layer in net:
    X = layer(X)
    print(layer.__class__.__name__,'output shape: \t',X.shape)

# 输出如下:
Conv2d output shape: torch.Size([1, 6, 28, 28])
Sigmoid output shape: torch.Size([1, 6, 28, 28])
AvgPool2d output shape: torch.Size([1, 6, 14, 14])
Conv2d output shape: torch.Size([1, 16, 10, 10])
Sigmoid output shape: torch.Size([1, 16, 10, 10])
AvgPool2d output shape: torch.Size([1, 16, 5, 5])
Flatten output shape: torch.Size([1, 400])

1.4 训练模型

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    nn.Conv2d(1, 6, kernel_size=5, padding=2), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Conv2d(6, 16, kernel_size=5), nn.Sigmoid(),
    nn.AvgPool2d(kernel_size=2, stride=2),
    nn.Flatten(),
    nn.Linear(16 * 5 * 5, 120), nn.Sigmoid(),
    nn.Linear(120, 84), nn.Sigmoid(),
    nn.Linear(84, 10))

batch_size = 256
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size=batch_size)

def evaluate_accuracy_gpu(net, data_iter, device=None): #@save
    """使用GPU计算模型在数据集上的精度"""
    if isinstance(net, nn.Module):
        net.eval() # 设置为评估模式
        if not device:
            device = next(iter(net.parameters())).device
    # 正确预测的数量,总预测的数量
    metric = d2l.Accumulator(2)
    with torch.no_grad():
        for X, y in data_iter:
            if isinstance(X, list):
                # BERT微调所需的(之后将介绍)
                X = [x.to(device) for x in X]
            else:
                X = X.to(device)
            y = y.to(device)
            metric.add(d2l.accuracy(net(X), y), y.numel())
    return metric[0] / metric[1]

def train_ch6(net, train_iter, test_iter, num_epochs, lr, device):
    """用GPU训练模型(在第六章定义)"""
    def init_weights(m):
        if type(m) == nn.Linear or type(m) == nn.Conv2d:
            nn.init.xavier_uniform_(m.weight)
    net.apply(init_weights)
    print('training on', device)
    net.to(device)
    optimizer = torch.optim.SGD(net.parameters(), lr=lr)
    loss = nn.CrossEntropyLoss()
    animator = d2l.Animator(xlabel='epoch', xlim=[1, num_epochs],legend=['train loss', 'train acc', 'test acc'])
    timer, num_batches = d2l.Timer(), len(train_iter)
    for epoch in range(num_epochs):
    # 训练损失之和,训练准确率之和,样本数
    metric = d2l.Accumulator(3)
    net.train()
    for i, (X, y) in enumerate(train_iter):
        timer.start()
        optimizer.zero_grad()
        X, y = X.to(device), y.to(device)
        y_hat = net(X)
        l = loss(y_hat, y)
        l.backward()
        optimizer.step()
        with torch.no_grad():
            metric.add(l * X.shape[0], d2l.accuracy(y_hat, y), X.shape[0])
        timer.stop()
        train_l = metric[0] / metric[2]
        train_acc = metric[1] / metric[2]
        if (i + 1) % (num_batches // 5) == 0 or i == num_batches - 1:
            animator.add(epoch + (i + 1) / num_batches, (train_l, train_acc, None))
    test_acc = evaluate_accuracy_gpu(net, test_iter)
    animator.add(epoch + 1, (None, None, test_acc))
print(f'loss {train_l:.3f}, train acc {train_acc:.3f}, 'f'test acc {test_acc:.3f}')
print(f'{metric[2] * num_epochs / timer.sum():.1f} examples/sec 'f'on {str(device)}')

# 开始训练
lr, num_epochs = 0.9, 10
train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

二、AlexNet

2.1 模型简介

AlexNet赢了2012年ImageNet比赛

是个更深更大的LeNet

相对LeNet主要改进:

        ∷ ReLu作为激活函数,减缓梯度消失

        ∷ 使用MaxPooling

        ∷ 全连接层后加入了丢弃层(DropOut

        ∷ 进行了数据增强(Data argumentation,截取图片一部分作为新增数据、或者调色温)

DropOut: 随机使某个神经元失效,以免训练后网络输出过度依赖某个神经元导致过拟合【深度学习】丢弃法(dropout)_苦逼的虾的博客-CSDN博客Dropout (nn.Dropout()) (为什么神经网络中的dropout可以作为正则化)(model.eval())(为什么Dropout可看作是一种集成学习)_hxxjxw的博客-CSDN博客

引起了计算机视觉方法论的改变,之前都是人工从图片提取特征,AlexNet使用CNN提取特征,如图3所示。

图3. 机器学习方法论的改变

         模型结构如下:

图4. AlexNet结构

         图中11×11卷积层(96)表示卷积核大小为11×11,输出通道数为96。

2.2 代码实现

        AlexNet结构和LeNet类似,也使用nn.Sequential作为构造器。

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    # 这里使用一个11*11的更大窗口来捕捉对象。
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
    nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
    nn.Linear(6400, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
    nn.Linear(4096, 10))

2.3 检查模型

检查模型即检查每层的名称及输出矩阵大小是否符合预期。

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    # 这里使用一个11*11的更大窗口来捕捉对象。
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
    nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
    nn.Linear(6400, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
    nn.Linear(4096, 10))


X = torch.randn(1, 1, 224, 224)
for layer in net:
    X=layer(X)
    print(layer.__class__.__name__,'output shape:\t',X.shape)

# 输出如下:
Conv2d output shape: torch.Size([1, 96, 54, 54])
ReLU output shape: torch.Size([1, 96, 54, 54])
MaxPool2d output shape: torch.Size([1, 96, 26, 26])
Conv2d output shape: torch.Size([1, 256, 26, 26])
ReLU output shape: torch.Size([1, 256, 26, 26])
MaxPool2d output shape: torch.Size([1, 256, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 384, 12, 12])
ReLU output shape: torch.Size([1, 384, 12, 12])
Conv2d output shape: torch.Size([1, 256, 12, 12])
ReLU output shape: torch.Size([1, 256, 12, 12])
MaxPool2d output shape: torch.Size([1, 256, 5, 5])
Flatten output shape: torch.Size([1, 6400])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])

2.4 训练模型

import torch
from torch import nn
from d2l import torch as d2l

net = nn.Sequential(
    # 这里使用一个11*11的更大窗口来捕捉对象。
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
    nn.Conv2d(256, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
    nn.Linear(6400, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
    nn.Linear(4096, 10))

batch_size = 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
lr, num_epochs = 0.01, 10
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

# 输出如下:
loss 0.327, train acc 0.879, test acc 0.866
3903.6 examples/sec on cuda:0

训练过程如图5所示。

图5. AlexNet训练过程

三、VGG

3.1 模型简介

        VGG是在AlexNet上改进而来,可以看作是一个更大更深的AlexNet。

        在同样计算开销下,深但窄的网络比浅但宽的网络好,因此VGG将AlexNet改造成更大更深的网络以提升性能。

        VGG是基于“块”的,VGG的“块”定义由多个卷积层和一个池化层组成,如图6所示。

图6. VGG块的定义

         VGG的整体结构即由多个VGG“块”和几个全连接层组成,如图7所示。

图7. VGG网络结构

3.2 代码实现

         VGG块的实现

import torch
from torch import nn
from d2l import torch as d2l

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
    return nn.Sequential(*layers)

        上述代码最后一行使用nn.Sequential(*layers)而不是nn.Sequential(layers),是因为前者等价于将layers数组中所有内容取出放入Sequential

        例如:layers=[net1, net2, net3]

        nn.Sequential(*layers)等价于nn.Sequential(net1, net2, net3)

        而nn.Sequential(layers)等价于nn.Sequential([net1, net2, net3])

        * 可以理解为C++中类似的意思,即取值。

        每个“块”里使用的卷积核大小均为3×3,padding=1,stride默认为1,假设输入层大小为m×n,那么该层输出为(m+2)-3+1=m,(n+2)-3+1=n,故卷积层的输入输出大小相同。

        池化层核尺寸为2×2,Stride=2,假设输入层大小为m×n,那么池化层输出为\frac{m-2}{2}+1=\frac{m}{2},n同理,因此每个VGG块的输出尺寸为输入的一半

import torch
from torch import nn
from d2l import torch as d2l

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
    return nn.Sequential(*layers)

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

def vgg(conv_arch):
    conv_blks = []
    in_channels = 1
    # 卷积层部分
    for (num_convs, out_channels) in conv_arch:
        conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels
    return nn.Sequential(
        *conv_blks, nn.Flatten(),
        # 全连接层部分
        nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 10))
net = vgg(conv_arch)

3.3 检查模型

import torch
from torch import nn
from d2l import torch as d2l

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
    return nn.Sequential(*layers)

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

def vgg(conv_arch):
    conv_blks = []
    in_channels = 1
    # 卷积层部分
    for (num_convs, out_channels) in conv_arch:
        conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels
    return nn.Sequential(
        *conv_blks, nn.Flatten(),
        # 全连接层部分
        nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 10))
net = vgg(conv_arch)

X = torch.randn(size=(1, 1, 224, 224))
for blk in net:
    X = blk(X)
    print(blk.__class__.__name__,'output shape:\t',X.shape)

# 输出如下:
Sequential output shape: torch.Size([1, 64, 112, 112])
Sequential output shape: torch.Size([1, 128, 56, 56])
Sequential output shape: torch.Size([1, 256, 28, 28])
Sequential output shape: torch.Size([1, 512, 14, 14])
Sequential output shape: torch.Size([1, 512, 7, 7])
Flatten output shape: torch.Size([1, 25088])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 4096])
ReLU output shape: torch.Size([1, 4096])
Dropout output shape: torch.Size([1, 4096])
Linear output shape: torch.Size([1, 10])

3.4 训练模型

import torch
from torch import nn
from d2l import torch as d2l

def vgg_block(num_convs, in_channels, out_channels):
    layers = []
    for _ in range(num_convs):
        layers.append(nn.Conv2d(in_channels, out_channels, kernel_size=3, padding=1))
        layers.append(nn.ReLU())
        in_channels = out_channels
    layers.append(nn.MaxPool2d(kernel_size=2,stride=2))
    return nn.Sequential(*layers)

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

def vgg(conv_arch):
    conv_blks = []
    in_channels = 1
    # 卷积层部分
    for (num_convs, out_channels) in conv_arch:
        conv_blks.append(vgg_block(num_convs, in_channels, out_channels))
        in_channels = out_channels
    return nn.Sequential(
        *conv_blks, nn.Flatten(),
        # 全连接层部分
        nn.Linear(out_channels * 7 * 7, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 4096), nn.ReLU(), nn.Dropout(0.5),
        nn.Linear(4096, 10))
net = vgg(conv_arch)

ratio = 4
small_conv_arch = [(pair[0], pair[1] // ratio) for pair in conv_arch]
net = vgg(small_conv_arch)

lr, num_epochs, batch_size = 0.05, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

# 输出如下
loss 0.179, train acc 0.934, test acc 0.920
2390.1 examples/sec on cuda:0

训练过程如图8所示。

图8. VGG训练过程

四、NiN(网络中的网络)

        NiN(NetWork in NetWork)是为了解决全连接层参数过多,容易造成过拟合的问题而提出。思想类似SharedMLP。使用大小为1×1的卷积核整合信息。

        NiN的基本单元为NiN块,一个NiN块由一个普通卷积层和2个SharedMLP组成,如图9所示。

图9. NiN Block 结构

        NiN网络参数少,不容易过拟合。

        NiN网络结构如下:

图10. NiN网络结构

         最后一层Global AvgPool表示池化过程中的核长宽和输入一致,对应pytorch中的函数为nn.AdaptiveAvgPool2d((1, 1))

        代码实现及训练和前述三个模型类似,不再赘述。

五、GoogLeNet(含并行连接的网络)

        设计GoogLeNet的动机是前面的网络通过不同的结构设计,起到了不同的效果,如今我有几个备选的网络结构,那么选择哪个能取到较好的效果?

        这个问题的答案很难得知,但是每种网络结构肯定都能提取某方面特征,既然这样,我就把所有备选的网络结构都用上去,那么就能获取这几种结构网络所能提取的所有类型的特征。

 

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Arnold置乱

一、Arnold置乱概述 Arnold变换是俄国数学家弗拉基米尔阿诺德(Vladimir Igorevich Arnold)提出,Arnold将其应用在遍历理论研究中。由于Arnold本人最初对一张猫的图片进行了此种变换,因此它又被称为猫脸变换(cat映射&am…

基于Citespace、vosviewer、R语言的文献计量学可视化分析技术及全流程文献可视化SCI论文高效写作方法

文献计量学是指用数学和统计学的方法,定量地分析一切知识载体的交叉科学。它是集数学、统计学、文献学为一体,注重量化的综合性知识体系。特别是,信息可视化技术手段和方法的运用,可直观的展示主题的研究发展历程、研究现状、研究…

HCIP-OpenStack组件之neutron

neutron(ovs、ovn) OVS OVS(Open vSwitch)是虚拟交换机,遵循SDN(Software Defined Network,软件定义网络)架构来管理的。 OVS介绍参考:https://mp.weixin.qq.com/s?__bizMzAwMDQyOTcwOA&mid2247485088&idx1…

基于AWS的3D模型搜索服务实现

3D模型广泛应用于计算机游戏、电影、工程、零售业、广告等许多领域。市场上有很多制作3D模型的工具,但几乎没有工具可以直观地搜索3D模型数据库以找到类似的3D模型 因为开发好的 3D 模型搜索工具非常具有挑战性。 它需要复杂的计算和 AI/ML 框架来创建模型描述符并提…

jmeter HTTP信息头管理器

首先,打开JMeter并创建一个新的测试计划。右键单击测试计划,选择"添加" > “线程组”,然后在线程组上右键单击,选择"添加" > “Sampler” > “HTTP请求”。 在HTTP请求中填写服务器的URL和其他必要…

Java基础之IO流File类创建及删除

1.File类概述及构造方法 2.File类创建功能 文件创建成功! 如果文件不存在,就创建文件,并返回true 如果文件存在,就不创建文件,并返回false 如果文件夹不存在,就创建文件夹,并返回true 如果文件…

【0基础入门Python Web笔记】三、python 之函数以及常用内置函数

三、python 之函数以及常用内置函数 函数函数定义函数调用函数参数返回值 常用内置函数input()函数range()函数其它 更多实战项目可进入下方官网 函数 函数是一种用于封装可重复使用代码块的工具,能够将一系列操作组织成一个逻辑单元。 函数定义 在Python中&…

【C语言】文件操作 -- 详解

一、什么是文件 磁盘上的文件是文件。 1、为什么要使用文件 举个例子,当我们想实现一个 “通讯录” 程序时,在通讯录中新建联系人、删除联系人等一系列操作,此时的数据存储于内存中,程序退出后所有数据都会随之消失。为了让通讯录…

Python爬虫分布式架构问题汇总

在使用Python爬虫分布式架构中可能出现以下的问题,我们针对这些问题,列出相应解决方案: 1、任务重复执行 在分布式环境下,多个爬虫节点同时从消息队列中获取任务,可能导致任务重复执行的问题。 解决方案:…

由JDK bug引发的线上OOM

由JDK bug引发的线上OOM 最近生产环境的一个应用忽然发生了OOM,还好是业务低峰期,没有导致什么严重问题,下面记录下本次排查的过程; 故障临时处理 在某天下午,正在愉快的写代码时,忽然看到业务反馈支付服…

湘潭大学 湘大 XTU OJ 1055 整数分类 题解(非常详细)

链接 整数分类 题目 Description 按照下面方法对整数x进行分类:如果x是一个个位数,则x属于x类;否则将x的各位上的数码累加,得到一个新的x,依次迭代,可以得到x的所属类。比如说24,246&#…

XXX程序 详细说明

用于记录理解PC程序的程序逻辑 1、程序的作用 根据原作者的说明(文件说明.txt),该程序 (PC.py) 的主要作用是提取某一个文件夹中的某个设备 (通过config中的信息看出来是Ag_T_8) 产生的日志文件,然后提取其中某些需要的数据&…

MyCAT命令行监控

9066端口 ,用mysql命令行连接 Mysql –utest –ptest –P9066 show help 可显示所有相关管理命令 显示后端物理库连接信息,包括当前连接数,端口 Show backend Show connection 显示当前前端客户端连接情况,已经网络流量信息、…

学习中ChatGPT的17种用法

ChatGPT本质上是一个聊天工具,旧金山的人工智能企业OpenAI于2022年11月正式推出ChatGPT。那么,ChatGPT与其他人工智能产品相比有什么特殊呢? 它除了可以回答结构性的问题,例如语法修正、翻译和查找答案之外。最关键的是它能够去解…

mysql--数据库的操作

数据库,是数据存储的最大单元。 1 创建数据库 create database mydatabase; 每次创建数据库的时候,都会多一个文件夹,关系型数据库是存储在磁盘当中的,所以这时候可以查看新建的数据库 2 指定字符集 MySQL中的字符集转换过程 制…

工程师是怎样对待开源

工程师如何对待开源 本文是笔者作为一个在知名科技企业内从事开源相关工作超过 20 年的工程师,亲身经历或者亲眼目睹很多工程师对待开源软件的优秀实践,也看到了很多 Bad Cases,所以想把自己的一些心得体会写在这里,供工程师进行…

三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析

三维模型OBJ格式轻量化压缩处理的数据质量提升方法分析 在三维模型的OBJ格式轻量化压缩处理过程中,除了减小文件大小和提高加载速度之外,我们也需要考虑如何提升数据质量。以下是几种常见的方法: 1、优化顶点数据:顶点数据是三维…

学习心得04:CUDA

2018年的时候,看过同事使用CUDA。因为工作忙,所以也没请教。 近来买了本入门的CUDA书,学习了一番。有两个心得: 工作拆分。 CUDA是并行计算,也就是大量重复的可拆分的计算。数组最符合这个要求。简单点就是把数组外面…

战略企业家派:企业家愿景形成的过程

战略企业家派:战略的是企业家愿景形成的过程【安志强趣讲267期】 趣讲大白话:企业家才是关键因素 **************************** 战略企业家派的代表是熊彼特 他认为企业家的职责在创新 只有创新才能赢得更多利润 创新是新产品或新生产方式的各种组合 提…