3. 使用PyTorch深度学习库训练第一个卷积神经网络CNN

news2024/11/25 20:29:08

这篇博客将介绍如何使用PyTorch深度学习库训练第一个卷积神经网络(CNN)。训练CNN使用 KMNIST 数据集(MNIST digits数据集的替代品,内置在PyTorch中)识别手写平假名字符(handwritten Hiragana characters)。

在图像数据集上训练CNN与在数字数据上训练基本的多层感知器(MLP)并没有什么不同。将包括:

  • 定义模型架构
  • 从磁盘加载数据集
  • 熟练使用PyTorch的数据加载器DataLoader
  • 循环纪元和数据批次
  • 预测并计算损失
  • 将梯度适当归零,执行反向传播,并更新模型参数
  • 将训练完成的PyTorch模型保存到磁盘
  • 在单独的Python脚本中从磁盘加载模型
  • 使用PyTorch模型对图像进行预测

谈到从磁盘加载保存的PyTorch模型,下篇博客将介绍如何使用预先训练的PyTorch模型来识别日常生活中经常遇到的1000个图像类。这些模型可以节省大量时间和麻烦-它们非常精确,不需要手动训练它们。

1. 效果图

训练CNN≈我的CPU上有271秒。使用GPU的培训时间减少到≈130秒。
在最后一个阶段结束时,获得了99.68%的训练精度和98.03%的验证精度。
当在测试集上进行评估时,达到了≈94%的准确率。考虑到平假名字符的复杂性和浅层网络架构的简单性,这是非常好的(使用更深层次的网络,如VGG启发的模型或类似ResNet的模型,可以获得更高的准确率,但这些模型更复杂)。

[INFO] loading the KMNIST dataset...
Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/train-images-idx3-ubyte.gz
Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/train-images-idx3-ubyte.gz to data\KMNIST\raw\train-images-idx3-ubyte.gz
18165760it [00:40, 443555.23it/s]                              
Extracting data\KMNIST\raw\train-images-idx3-ubyte.gz to data\KMNIST\raw

Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/train-labels-idx1-ubyte.gz
Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/train-labels-idx1-ubyte.gz to data\KMNIST\raw\train-labels-idx1-ubyte.gz
29696it [00:00, 298773.88it/s]           
Extracting data\KMNIST\raw\train-labels-idx1-ubyte.gz to data\KMNIST\raw

Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/t10k-images-idx3-ubyte.gz
Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/t10k-images-idx3-ubyte.gz to data\KMNIST\raw\t10k-images-idx3-ubyte.gz
3041280it [00:13, 222871.32it/s]                             
Extracting data\KMNIST\raw\t10k-images-idx3-ubyte.gz to data\KMNIST\raw

Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/t10k-labels-idx1-ubyte.gz
Downloading http://codh.rois.ac.jp/kmnist/dataset/kmnist/t10k-labels-idx1-ubyte.gz to data\KMNIST\raw\t10k-labels-idx1-ubyte.gz
100%|██████████| 5120/5120 [00:00<?, ?it/s]
Extracting data\KMNIST\raw\t10k-labels-idx1-ubyte.gz to data\KMNIST\raw

[INFO] generating the train/validation split...
[INFO] initializing the LeNet model...
[INFO] training the network...
[INFO] EPOCH: 1/10
Train loss: 0.344304, Train accuracy: 0.8940
Val loss: 0.148819, Val accuracy: 0.9535

[INFO] EPOCH: 2/10
Train loss: 0.100273, Train accuracy: 0.9696
Val loss: 0.080464, Val accuracy: 0.9773

[INFO] EPOCH: 3/10
Train loss: 0.058563, Train accuracy: 0.9824
Val loss: 0.089331, Val accuracy: 0.9728

[INFO] EPOCH: 4/10
Train loss: 0.037242, Train accuracy: 0.9883
Val loss: 0.087128, Val accuracy: 0.9757

[INFO] EPOCH: 5/10
Train loss: 0.026911, Train accuracy: 0.9910
Val loss: 0.093474, Val accuracy: 0.9756

[INFO] EPOCH: 6/10
Train loss: 0.019837, Train accuracy: 0.9937
Val loss: 0.075803, Val accuracy: 0.9807

[INFO] EPOCH: 7/10
Train loss: 0.015524, Train accuracy: 0.9948
Val loss: 0.066136, Val accuracy: 0.9834

[INFO] EPOCH: 8/10
Train loss: 0.012120, Train accuracy: 0.9959
Val loss: 0.078302, Val accuracy: 0.9814

[INFO] EPOCH: 9/10
Train loss: 0.010891, Train accuracy: 0.9964
Val loss: 0.089176, Val accuracy: 0.9811

[INFO] EPOCH: 10/10
Train loss: 0.009471, Train accuracy: 0.9968
Val loss: 0.087064, Val accuracy: 0.9803

[INFO] total time taken to train the model: 271.64s
[INFO] evaluating network...
              precision    recall  f1-score   support

           o       0.93      0.97      0.95      1000
          ki       0.97      0.92      0.94      1000
          su       0.90      0.91      0.90      1000
         tsu       0.96      0.96      0.96      1000
          na       0.97      0.91      0.94      1000
          ha       0.97      0.92      0.94      1000
          ma       0.87      0.98      0.92      1000
          ya       0.98      0.94      0.96      1000
          re       0.97      0.96      0.97      1000
          wo       0.96      0.96      0.96      1000

    accuracy                           0.94     10000
   macro avg       0.95      0.94      0.94     10000
weighted avg       0.95      0.94      0.94     10000

如下图所示,训练损失/准确度的历史图是平滑的,表明几乎没有发生过拟合。
在这里插入图片描述

在测试集上随机选取10个样本,可以看到均能成功检测,效果图如下:
识别正确蓝色,识别错误红色。

在这里插入图片描述

2. 环境配置

pip install torch torchvision
pip install opencv-contrib-python
pip install scikit-learn

3. KMNIST数据集

  • 使用Kuzushiji MNIST数据集,简称KMNIST(MNIST digits数据集的替代品)。此数据集旨在替代标准MNIST数字识别数据集。

  • KMNIST数据集由70000张图像及其相应标签组成(60000张用于培训,10000张用于测试)。

  • KMNIST数据集中共有10个类(表示10个字符),每个类都是均匀分布和表示的。目标是训练一个能够准确分类这10个字符的CNN。

  • KMNIST数据集内置在PyTorch中。

4. 源码

lenet.py: 使用PyTorch实现了著名的LeNet CNN结构
train_lenet.py: 使用PyTorch在KMNIST数据集上训练LeNet CNN网络,并将训练过的模型序列化到磁盘
predict.py: 从磁盘加载模型,在测试集照片上预测结果,展示结果到屏幕
output/: 存放训练/验证损失/准确度图和模型;

4.1 lenet.py

# lenet.py
# 这里用PyTorch实现的卷积神经网络(CNN)是一种开创性的LeNet架构
# LeNet是一个非常浅层的神经网络,由以下几层组成:(CONV=>RELU=>POOL)*2=>FC=>RELU=>FC=>SOFTMAX

# 导入必要的包
from torch import flatten  # 展平多维卷(例如CONV或POOL层)的输出,以便可以对其应用完全连接的层
from torch.nn import Conv2d  # PyTorch实现卷积层
from torch.nn import Linear  # 完全连接的层
from torch.nn import LogSoftmax  # 用于构建softmax分类器以返回每个类的预测概率
from torch.nn import MaxPool2d  # 应用MaxPool2d以减少输入层的空间维度

from torch.nn import Module  # 与使用Sequential PyTorch类来实现LeNet不同,将对模块对象进行子类化,以便可以看到PyTorch如何使用类来实现神经网络
from torch.nn import ReLU  # ReLU激活函数


class LeNet(Module):
    # 模块的构造函数仅初始化层类型。PyTorch跟踪这些变量,但它不知道这些层是如何相互连接的。
    # 为了让PyTorch了解您正在构建的网络架构,需要定义forward功能。
    # 在forward函数中,获取构造函数中初始化的变量并连接它们。
    # 借助autograd模块,PyTorch可以使用您的网络进行预测并执行自动反向传播
    def __init__(self, numChannels, classes):
        # 调用构造器
        super(LeNet, self).__init__()

        # 第一个CONV层共学习20个过滤器,每个过滤器为5×5。然后应用ReLU激活函数,然后是2×2最大池层和2×2步幅,以减少输入图像的空间维度。
        # 初始化第一层:CONV => RELU => POOL layers
        self.conv1 = Conv2d(in_channels=numChannels, out_channels=20,
                            kernel_size=(5, 5))
        self.relu1 = ReLU()
        self.maxpool1 = MaxPool2d(kernel_size=(2, 2), stride=(2, 2))

        # 第二组CONV=>RELU=>POOL层。我们将CONV层中学习的过滤器数量增加到50个,但保持5×5的内核大小。再次应用ReLU激活,然后是最大池。
        # 初始化第二层:CONV => RELU => POOL layers
        self.conv2 = Conv2d(in_channels=20, out_channels=50,
                            kernel_size=(5, 5))
        self.relu2 = ReLU()
        self.maxpool2 = MaxPool2d(kernel_size=(2, 2), stride=(2, 2))

        # 初始化第一组(也是唯一一组) FC => RELU layers
        # 第一组也是唯一一组完全连接的层。定义层的输入数量(800)以及所需的输出节点数量(500)。在FC层之后进行ReLu激活。
        self.fc1 = Linear(in_features=800, out_features=500)
        self.relu3 = ReLU()

        # 初始化 softmax 分类器
        # 最后应用softmax分类器。features的数量设置为500,这是前一层的输出维度。
        # 然后应用LogSoftmax,以便在评估期间获得预测概率。
        self.fc2 = Linear(in_features=500, out_features=classes)
        self.logSoftmax = LogSoftmax(dim=1)

    # forward方法接受单个参数x,它是网络的一批输入数据。
    # 然后,将conv1、relu1和maxpool1层连接在一起,形成网络的第一个CONV=>RELU=>POOL层。
    # 构建了第二组CONV=>RELU=>POOL层。
    # 此时,变量x是多维张量;然而,为了创建完全连接的层,需要将这个张量“展平”为基本上相当于1D值列表的张量。
    # 将fc1和relu3层连接到网络架构,然后连接最终的fc2和logSoftmax。
    #
    # 重要的是要理解,__init__所做的只是初始化变量。PyTorch完全不知道网络架构是什么,只知道LeNet类定义中存在一些变量。
    # 为了构建网络体系结构本身(即输入到其他层的是哪一层),需要重写模块类的forward方法。
    # forward功能有:
    # 将层/子网络从类的构造函数(即__init__)中定义的变量连接在一起
    # 定义了网络体系结构本身
    # 允许模型向前传递,从而产生输出预测
    # 由于PyTorch的autograd模块,它允许执行自动微分并更新模型权重
    def forward(self, x):
        # 将input输入到第一层 CONV => RELU => POOL layers
        x = self.conv1(x)
        x = self.relu1(x)
        x = self.maxpool1(x)

        # 将上一层的输出传递到第二层 CONV => RELU => POOL layers
        x = self.conv2(x)
        x = self.relu2(x)
        x = self.maxpool2(x)

        # 展开上一层的输出,传递到唯一的完全连接层 FC => RELU layers
        x = flatten(x, 1)
        x = self.fc1(x)
        x = self.relu3(x)

        # 传递输出到sofmax分类器,以获取预测结果
        x = self.fc2(x)
        output = self.logSoftmax(x)

        # 返回预测的输出结果
        return output

4.2 train_lenet.py

# USAGE
# python train_lenet.py --model output/model.pth --plot output/plot.png

# 设置matplotlib backend以保存图片到磁盘
import matplotlib

matplotlib.use("Agg")

# 导入必要的包
from p220625.pyimagesearch.lenet import LeNet  # LeNet CNN的PyTorch实现
from sklearn.metrics import classification_report  # 用于在测试集上显示详细的分类报告
from torch.utils.data import random_split  # 从输入数据集构造随机训练/测试集拆分
from torch.utils.data import DataLoader  # 强大的数据加载器允许轻松构建数据管道来训练CNN
from torchvision.transforms import ToTensor  # 预处理函数,可自动将输入数据转换为PyTorch张量
from torchvision.datasets import KMNIST  # Kuzushiji MNIST数据集加载器内置在PyTorch库中

from torch.optim import Adam  # 用来训练神经网络的优化器
from torch import nn  # PyTorch的神经网络实现
import matplotlib.pyplot as plt
import numpy as np
import argparse
import torch
import time

# 构建命令行参数及解析
# --model 序列化模型的存放路径
# --plot 损失/准确度图存放路径
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", type=str, required=False, default='output/model.pth',
                help="path to output trained model")
ap.add_argument("-p", "--plot", type=str, required=False, default='output/plot.png',
                help="path to output loss/accuracy plot")
args = vars(ap.parse_args())

# 定义训练超参数(hyperparameters)初始学习率、批量大小和要训练的纪元数
INIT_LR = 1e-3
BATCH_SIZE = 64
EPOCHS = 10

# 定义训练和测试级拆分比率 75%训练集,25%测试集
TRAIN_SPLIT = 0.75
VAL_SPLIT = 1 - TRAIN_SPLIT

# 设置训练模型要使用的设备(CPU or GPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 使用PyTorch的内置KMNIST类加载KMNIST数据集
# download=True标志表示,如果之前没有下载KMNIST数据集,PyTorch将自动下载并将其缓存到磁盘。
# 还要注意transform参数-这里可以应用许多数据转换。这里需要的唯一转换是将PyTorch加载的NumPy数组转换为张量数据类型。
print("[INFO] loading the KMNIST dataset...")
trainData = KMNIST(root="data", train=True, download=True,
                   transform=ToTensor())
testData = KMNIST(root="data", train=False, download=True,
                  transform=ToTensor())

# 计算训练/测试样本数
print("[INFO] generating the train/validation split...")
numTrainSamples = int(len(trainData) * TRAIN_SPLIT)
numValSamples = int(len(trainData) * VAL_SPLIT)
(trainData, valData) = random_split(trainData,
                                    [numTrainSamples, numValSamples],
                                    generator=torch.Generator().manual_seed(42))

# 现在有三组数据:训练、验证、测试
# 为每个数据集创建一个数据加载器
# 仅为trainDataLoader设置shuffle=True,因为验证和测试集不需要洗牌。
trainDataLoader = DataLoader(trainData, shuffle=True,
                             batch_size=BATCH_SIZE)
valDataLoader = DataLoader(valData, batch_size=BATCH_SIZE)
testDataLoader = DataLoader(testData, batch_size=BATCH_SIZE)

# 为训练和验证集计算每个纪元的步长
trainSteps = len(trainDataLoader.dataset) // BATCH_SIZE
valSteps = len(valDataLoader.dataset) // BATCH_SIZE

# 初始化LeNet模型
print("[INFO] initializing the LeNet model...")
model = LeNet(
    numChannels=1,
    classes=len(trainData.dataset.classes)).to(device)

# 初始化优化器和损失函数
# 在模型定义中,组合nn.NLLLoss类与LogSoftmax,得到了分类交叉熵损失(这相当于训练一个具有输出线性层和nn.CrossEntropyLoss损失的模型)
opt = Adam(model.parameters(), lr=INIT_LR)
lossFn = nn.NLLLoss()

# 初始化字典存储训练历史
H = {
    "train_loss": [],
    "train_acc": [],
    "val_loss": [],
    "val_acc": []
}

# 计算训练模型耗时
print("[INFO] training the network...")
startTime = time.time()

# 遍历纪元
for e in range(0, EPOCHS):
    # 设置模型为训练模式
    model.train()

    # 初始化总的训练损失和验证损失
    totalTrainLoss = 0
    totalValLoss = 0

    # 初始化训练准确率和验证准确率
    trainCorrect = 0
    valCorrect = 0

    # 在DataLoader上遍历训练集
    # PyTorch自动生成一批训练数据。在幕后数据加载器也在洗牌训练数据(如果做任何额外的预处理或数据扩充,也在这里进行)。
    for (x, y) in trainDataLoader:
        # 传递输入到设备
        (x, y) = (x.to(device), y.to(device))

        # 执行预测,计算训练损失
        pred = model(x)
        loss = lossFn(pred, y)

        # 梯度归零,执行反向传播,更新模型参数(权重)
        opt.zero_grad()
        loss.backward()
        opt.step()

        # 将损失添加到迄今为止的培训总损失中,并计算正确预测的数量
        totalTrainLoss += loss
        trainCorrect += (pred.argmax(1) == y).type(
            torch.float).sum().item()

    # 训练完,在验证集上验证模型
    # 转换到自动微分以进行验证
    with torch.no_grad():  # 使用torch.no_grad()以关闭梯度追踪和计算的上下文
        # 设置模型到验证模式
        model.eval()

        # 遍历验证数据集
        for (x, y) in valDataLoader:
            # 传递输入到设备
            (x, y) = (x.to(device), y.to(device))

            # 预测并计算验证损失
            pred = model(x)
            totalValLoss += lossFn(pred, y)

            # 计算正确的预测数
            valCorrect += (pred.argmax(1) == y).type(
                torch.float).sum().item()

    # 计算平均验证和训练损失
    avgTrainLoss = totalTrainLoss / trainSteps
    avgValLoss = totalValLoss / valSteps

    # 计算平均训练和验证准确率
    trainCorrect = trainCorrect / len(trainDataLoader.dataset)
    valCorrect = valCorrect / len(valDataLoader.dataset)

    # 更新训练历史字典
    H["train_loss"].append(avgTrainLoss.cpu().detach().numpy())
    H["train_acc"].append(trainCorrect)
    H["val_loss"].append(avgValLoss.cpu().detach().numpy())
    H["val_acc"].append(valCorrect)

    # 打印模型训练和验证信息
    # 在终端上显示训练损失、训练精度、验证损失和验证精度
    print("[INFO] EPOCH: {}/{}".format(e + 1, EPOCHS))
    print("Train loss: {:.6f}, Train accuracy: {:.4f}".format(
        avgTrainLoss, trainCorrect))
    print("Val loss: {:.6f}, Val accuracy: {:.4f}\n".format(
        avgValLoss, valCorrect))

# 结束耗时统计,并显示耗时
endTime = time.time()
print("[INFO] total time taken to train the model: {:.2f}s".format(
    endTime - startTime))

# 在测试集上验证cnn模型
print("[INFO] evaluating network...")

# 关闭自动微分以进行测试集验证
with torch.no_grad():
    # 设置模型为验证模式
    model.eval()

    # 初始化list以存储预测结果
    preds = []

    # 遍历测试集
    for (x, y) in testDataLoader:
        # 传递数据到设备
        x = x.to(device)

        # 预测并将顶级预测结果添加到结果list
        pred = model(x)
        preds.extend(pred.argmax(axis=1).cpu().numpy())

# 生成分类报告
print(classification_report(testData.targets.cpu().numpy(),
                            np.array(preds), target_names=testData.classes))

# 为训练历史生成matplotlib图(绘制训练损失和准确度图)
# 然后将模型权重序列化到磁盘:
plt.style.use("ggplot")
plt.figure()
plt.plot(H["train_loss"], label="train_loss")
plt.plot(H["val_loss"], label="val_loss")
plt.plot(H["train_acc"], label="train_acc")
plt.plot(H["val_acc"], label="val_acc")
plt.title("Training Loss and Accuracy on Dataset")
plt.xlabel("Epoch #")
plt.ylabel("Loss/Accuracy")
plt.legend(loc="lower left")
plt.savefig(args["plot"])

# 序列化模型到磁盘
torch.save(model, args["model"])

4.3 predict.py

# USAGE
# python predict.py --model output/model.pth


# 设置numpy种子以获得更好的再现性 reproducibility(设置NumPy随机种子,以提高跨机器的再现性。)
import numpy as np

np.random.seed(42)

# 导入必要的包
from torch.utils.data import DataLoader  # 强大的数据加载器允许轻松构建数据管道来训练CNN,用于加载KMNIST测试数据
from torch.utils.data import Subset  # 构建测试数据的子集
from torchvision.transforms import ToTensor  # 将输入数据转换为PyTorch张量数据类型
from torchvision.datasets import KMNIST  # PyTorch库中内置的Kuzushiji MNIST数据集加载器
import argparse
import imutils
import torch
import cv2  # OpenCV绑定,用于在屏幕上进行基本绘图和显示输出图像

# 构建命令行参数及解析
# --model 磁盘的模型文件路径
ap = argparse.ArgumentParser()
ap.add_argument("-m", "--model", type=str, required=False, default='output/model.pth',
                help="path to the trained PyTorch model")
args = vars(ap.parse_args())

# 设置训练模型要使用的设备(CPU or GPU)
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")

# 加载KMNIST数据集,随机获取10个数据点
print("[INFO] loading the KMNIST test dataset...")
testData = KMNIST(root="data", train=False, download=True,
                  transform=ToTensor())
idxs = np.random.choice(range(0, len(testData)), size=(10,))
# 使用Subset类(创建完整测试数据的较小“视图”)
testData = Subset(testData, idxs)

# 初始化测试集加载器
testDataLoader = DataLoader(testData, batch_size=1)

# 加载模型,并设置为验证模式
model = torch.load(args["model"]).to(device)
model.eval()

# 转换自动微分
# 使用torch.no_grad()以关闭梯度追踪和计算的上下文
with torch.no_grad():
    # 遍历测试集
    for i, (image, label) in enumerate(testDataLoader):
        # 获取原始图像及实际标签
        # 抓取当前图像并将其转换为NumPy数组(以便稍后使用OpenCV绘制)
        origImage = image.numpy().squeeze(axis=(0, 1))
        gtLabel = testData.dataset.classes[label.numpy()[0]]

        # 传递数据到设备,并用经过训练的LeNet模型进行预测
        image = image.to(device)
        pred = model(image)

        # 提取具有最高预测概率的类标签
        idx = pred.argmax(axis=1).cpu().numpy()[0]
        predLabel = testData.dataset.classes[idx]

        # KMNIST数据集中的每个图像都是单通道灰度图像;然而希望使用OpenCV的cv2。putText函数在图像上绘制预测类标签和实际的真实值标签。
        # 要在灰度图像上绘制RGB颜色,首先需要通过将灰度图像按深度累计三次来创建灰度图像的RGB表示
        # 此外调整了原始图像的大小,以便在屏幕上更容易看到它(默认情况下,KMNIST图像只有28×28像素,这可能很难看到,尤其是在高分辨率监视器上)。
        # 转换灰度图为RGB图像以进行绘制
        # 保留宽高比的缩放为宽度128
        origImage = np.dstack([origImage] * 3)
        origImage = imutils.resize(origImage, width=128)

        # 绘制预测的类标签在图像上
        color = (0, 255, 0) if gtLabel == predLabel else (0, 0, 255)
        cv2.putText(origImage, gtLabel, (2, 25),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.95, color, 2)

        # 打印结果在终端,并展示原始图像
        print("[INFO] ground truth label: {}, predicted label: {}".format(
            gtLabel, predLabel))
        cv2.imshow("image" + str(i + 1), origImage)
        cv2.waitKey(0)

参考

  • https://pyimagesearch.com/2021/07/19/pytorch-training-your-first-convolutional-neural-network-cnn/

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

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

相关文章

图的二种遍历-广度优先遍历和深度优先遍历

图的广度优先遍历 1.树的广度优先遍历 这样一个图中&#xff0c;是如何实现广度优先遍历的呢&#xff0c;首先&#xff0c;从1遍历完成之后&#xff0c;在去遍历2,3,4&#xff0c;最后遍历5 &#xff0c;6 , 7 , 8。这也就是为什么叫做广度优先遍历&#xff0c;是一层一层的往…

36个数据分析方法与模型

目录一、战略与组织二、质量与生产三、营销服务四、财务管理五、人力资源六、互联网运营好的数据分析师不仅熟练地掌握了分析工具&#xff0c;还掌握了大量的数据分析方法和模型。这样得出的结论不仅具备条理性和逻辑性&#xff0c;而且还更具备结构化和体系化&#xff0c;并保…

Python连接MYSQL、SQL Server、Oracle数据入库一网打尽

描述&#xff1a; Python众所周知用来数据提取&#xff0c;通俗说用来抓数据&#xff0c;将拿到的数据进行数据清洗、加工,分析等等。而其中最重要的部分就是数据爬取、数据入库这两部分了&#xff0c;至于数据分析那就特别考察你的SQL能力&#xff0c;如果是自己设计页面&…

马齿苋多糖偶联顺铂复合物/黄连素偶联顺铂化合物/载顺铂mPEg-PGA纳米微球制备方法

小编今天整理了马齿苋多糖偶联顺铂复合物/黄连素偶联顺铂化合物/载顺铂mPEg-PGA纳米微球制备方法&#xff0c;一起来看&#xff01; 黄连素偶联顺铂化合物制备方法: 以A549/DDP细胞为研究对象,分别加入12 μg/mL的顺铂,浓度为20 μmol/L,40 μmol/L,80 μmol/L的黄连素12 μg/…

艾美捷EndoGrade卵清蛋白重组示例说明

卵清蛋白是一种优质蛋白质&#xff0c;占蛋清蛋白总量的 54%-69%&#xff0c;卵清蛋白是典型的球蛋白&#xff0c;分子量为 44.5k Da&#xff0c;属含磷糖蛋白&#xff0c;含有四个自由巯基、385 个氨基酸残基。这些氨基酸残基相互缠绕折叠形成具有高度二级结构的球型结构&…

spring cache (默认方式)

目录前置pom配置示列代码效果图部分源码关键类流程代码描述 (此类无用, 只是备注源码的逻辑)前置 什么是springcache: 通过注解就能实现缓存功能, 简化在业务中去操作缓存 Spring Cache只是提供了一层抽象, 底层可以切换不同的cache实现. 通过CacheManager接口来统一不同的缓存…

大数据培训课程MapTask工作机制

MapTask工作机制 MapTask工作机制如图4-12所示。 图4-12 MapTask工作机制 &#xff08;1&#xff09;Read阶段&#xff1a;MapTask通过用户编写的RecordReader&#xff0c;从输入InputSplit中解析出一个个key/value。 &#xff08;2&#xff09;Map阶段&#xff1a;该节点主要…

java面试强基(9)

字符串拼接用“” 还是 StringBuilder? ​ Java 语言本身并不支持运算符重载&#xff0c;“”和“”是专门为 String 类重载过的运算符&#xff0c;也是 Java 中仅有的两个重载过的运算符。 ​ 字符串对象通过“”的字符串拼接方式&#xff0c;实际上是通过 StringBuilder 调…

【MFC】一个最简单的MFC程序(9)

了解完MFC程序的流程后&#xff0c;会有 “果然不需要了解这些东西&#xff0c;直接用就可以了” 的感觉。这应该是MFC的初衷吧——按照框架来&#xff0c;集中精力做应用。但是没有了解呢&#xff1f; 最简单的MFC程序 步骤&#xff1a; 1、创建WIN32应用程序&#xff0c;空…

GoWeb 的 MVC 入门实战案例,基于 Iris 框架实现(附案例全代码)

1、什么是 MVC M 即 Model 模型是指模型表示业务规则。在MVC的三个部件中&#xff0c;模型拥有最多的处理任务。被模型返回的数据是中立的&#xff0c;模型与数据格式无关&#xff0c;这样一个模型能为多个视图提供数据&#xff0c;由于应用于模型的代码只需写一次就可以被多个…

1531_AURIX_TriCore内核架构_任务以及函数

全部学习汇总&#xff1a; GreyZhang/g_tricore_architecture: some learning note about tricore architecture. (github.com) 继续前面的内核架构学习&#xff0c;这次看一下任务以及函数的描述。 1. 在嵌入式系统中&#xff0c;内核以及函数的设计其实是有一定的模型或者说是…

day33 文件上传中间件解析漏洞编辑器安全

前言 先判断中间件&#xff0c;是否有解析漏洞&#xff0c;字典扫描拿到上传点&#xff0c;或者会员中心&#xff0c;有可能存在文件上传的地方&#xff0c;而后测试绕过/验证&#xff0c;根据实际情况判断是白名单、黑名单还是内容其他的绕过&#xff0c;绕过/验证和中间件的…

数字信号处理FFT快速傅立叶变换MATLAB实现——实例

今天做作业的时候发现要对一个信号进行FFT变换&#xff0c;在网上找了半天也没找到个能看懂的&#xff08;因为我太菜了&#xff09;&#xff0c;后来自己研究了一下&#xff0c;感觉一知半解的 起因是这道作业题 例题-满足奈奎斯特 我画了两个图&#xff0c;一个是原信号经过…

毕业论文管理系统的设计与实现

摘要 随着互联网技术的迅猛发展&#xff0c;网络给人们带来了很多便利&#xff0c;比如人们借助于网络进行相互交流、相互通信、共享信息、文件的上传下载等。在线毕业论文管理系统就是以上运用之一&#xff0c;它已经广泛的应用于目前的各大高校,但现有的这些系统都有一定的局…

如何在VScode和Jetbrain上使用备受争议的GitHub Copilot

如何在VScode和Jetbrain上使用备受争议的GitHub Copilot VSCDOE https://docs.github.com/en/copilot/quickstart 配置好之后&#xff0c;就是这种效果&#xff0c;真实太NB了&#xff01;&#xff01;&#xff01; 一个tab就把所有的代码都填充上去了&#xff01; Jetbrain…

MES系统以全流程优化为核心,实现全闭环的生产

MES系统是一个在车间中广泛使用的软件&#xff0c;它具有承上启下的功能.该系统采用企业ERP系统&#xff0c;获取计划、资源等数据&#xff0c;并与PLM、SRM、WMS等进行整合&#xff0c;获取BOM、流程等数据。该系统可对下级的控制系统进行操作&#xff0c;并将作业命令和恢复计…

Prometheus Operator 极简配置方式在k8s一条龙安装Prometheus 监控

在k8s上 Prometheus&#xff08;普罗米修斯&#xff09; 监控&#xff0c;需要部署各种组件&#xff0c;比如Prometheus、Alertmanager、Grafana。同时各个组件的配置文件也是需要到处各个配置&#xff0c;Prometheus配置监控服务时&#xff0c;你还要知道各个监控服务的地址&a…

JDBC编程

JDBC编程 [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-5QlM7GTR-1669108965995)(https://img1.baidu.com/it/u865461056,274570923&fm253&fmtauto&app138&fPNG?w794&h500)] 什么是JDBC Java数据库连接 Java Database Connect…

第2-4-2章 规则引擎Drools入门案例-业务规则管理系统-组件化-中台

文章目录3. Drools入门案例3.1 业务场景说明3.2 开发实现3.3 小结3.3.1 规则引擎构成3.3.2 相关概念说明3.3.3 规则引擎执行过程3.3.4 KIE介绍3. Drools入门案例 全套代码及资料全部完整提供&#xff0c;点此处下载 本小节通过一个Drools入门案例来让大家初步了解Drools的使用…

Java 集合学习笔记:HashMap

Java 集合学习笔记&#xff1a;HashMapUML简介阅读源码属性字段1. 静态属性2.成员属性静态内部类class Node<K,V>静态工具方法hash(Object key)comparableClassFor(Object x)compareComparables(Class<?> kc, Object k, Object x)tableSizeFor(int cap)构造方法Ha…