基于VGG16的猫狗数据集分类

目录

  • 1. 作者介绍
  • 2. VGG16介绍
    • 2.1 背景介绍
    • 2.2 VGG16 结构
  • 3. Cat VS Dog数据集介绍
  • 4. 实验过程
    • 4.1 数据集处理
    • 4.2 训练部分设置
    • 4.3 训练结果
    • 4.4 问题分析
    • 4.5 单张图片测试
  • 5.完整训练代码与权重
  • 参考文献


1. 作者介绍

孙思伟,男,西安工程大学电子信息学院,2023级研究生
研究方向:深度强化学习与人工智能
电子邮件:sunsiwei0109@163.com

2. VGG16介绍

2.1 背景介绍

VGG16 是由牛津大学的K. Simonyan 和A. Zisserman 在论文“Very Deep Convolutional Networks for Large-Scale Image Recognition”中提出的卷积神经网络模型。该模型在 ImageNet 中实现了 92.7% 的前 5 名测试准确率,ImageNet 是一个包含 1000 个类别的 1400 多万张图像的数据集。它是提交给ILSVRC-2014的著名模型之一。它通过将大型内核大小的滤波器(第一层和第二卷积层分别为 11 个和 5 个)替换为多个 3×3 个内核大小的滤波器来改进 AlexNet。
论文地址: Very Deep Convolutional Networks for Large-Scale Image Recognition

2.2 VGG16 结构

VGG16 是一个流行的卷积神经网络(CNN)架构,主要用于图像识别和处理。它由多个卷积层、激活层、池化层和全连接层组成,图1为VGG网络结构图,具体如下:
在这里插入图片描述

  1. 输入层:接受大小为 224 x 224 x 3 的图像,这意味着每个图像有 224 x 224 像素,每个像素有 3 个颜色通道(红、绿、蓝)。
  2. 卷积层和ReLU激活层
    • 前两个卷积层各有 64 个过滤器,大小均为 3x3,步长为 1,通过ReLU激活函数进行非线性处理。
    • 接下来是两个卷积层,每层 128 个过滤器,过滤器大小和步长不变,同样使用ReLU激活。
    • 然后是三个卷积层,每层有 256 个过滤器。
    • 最后是三组卷积层,每组包含三个卷积层,每层有 512 个过滤器。
  3. 最大池化层(Max Pooling)
    • 每几个卷积层后会跟一个最大池化层,用于降低空间尺寸(特征图的高度和宽度),池化窗口大小通常为 2x2,步长为 2。
  4. 全连接层
    • 网络末端有三个全连接层。前两个全连接层各有 4096 个神经元,并使用ReLU激活函数。
    • 最后一个全连接层有 1000 个输出单元,对应于 1000 个类别的分类任务。
  5. Softmax层
    • 最终输出通过softmax层,该层将网络输出转换为概率分布,用于多类别分类。

VGG16 的特点是使用了很多堆叠的小卷积核(3x3),这样设计的好处是可以在保持感受野的情况下减少参数数量,提高网络的深度以学习更复杂的特征。整个网络架构简单但效果显著,适用于各种图像识别任务。

3. Cat VS Dog数据集介绍

猫狗大战(Cats vs. Dogs)数据集是一个用于二分类的图像识别任务的公开数据集,其目的是让机器学习模型能够区分图像是猫还是狗。
数据集最初由Kaggle在2013年为一个竞赛提供,现在已经成为计算机视觉和深度学习领域中一个非常流行的入门级数据集。图2是数据集内容。
数据集下载地址:Cats-vs-Dogs

Cats vs. Dogs数据集

数据集特点

  1. Number of data sets

    • 数据集包含25,000张彩色图像,其中猫和狗各占一半,即12,500张猫的图片和12,500张狗的图片。
  2. Data set size

    • 图片的大小不一,格式为.JPG。这为处理图像时的预处理步骤(如缩放、裁剪)提供了实际的挑战。
  3. Data set label

    • 每张图片都明确标记为“猫”或“狗”,这简化了监督学习模型的训练过程。

应用方向

  • 训练深度学习模型:这个数据集广泛用于训练各种深度学习模型,如卷积神经网络(CNN),来识别和分类图像内容。
  • 模型评估和比较:数据集也常用于评估不同模型和算法的性能,以及比较各种优化技术的效果。

挑战

  • 图像多样性:由于数据集中的图像在姿势、大小、背景和光照条件等方面都有很大的不同,这给模型的泛化能力带来了挑战。
  • 不均匀的图像质量:部分图像可能质量较低,或者包含干扰的背景元素,这需要更复杂的数据预处理或更强大的模型来克服。

4. 实验过程

4.1 数据集处理

  1. 安装并导入需要的模块:
import torch
import torch.nn as nn
import torch.optim as optim
from torchvision import datasets, models, transforms
from torch.utils.data import DataLoader
import os
import shutil
import numpy as np
from concurrent.futures import ThreadPoolExecutor
import matplotlib.pyplot as plt
  1. [2] 数据集划分
    我这里下载的数据集路径格式为:
    Dog_Cat
    ├─Dog
    └─Cat
    需要划分并将数据集设置为:
    Dog_Cat
    ├─train
    │ ├─cat
    │ └─dog
    └─valid
    ├─cat
    └─dog
#数据集划分
def create_train_valid_dirs(base_dir):
    #创建训练集和验证集的目录结构
    classes = ['dog', 'cat']
    for cls in classes:
        os.makedirs(os.path.join(base_dir, 'train', cls), exist_ok=True)
        os.makedirs(os.path.join(base_dir, 'valid', cls), exist_ok=True)

def copy_files(src_files, target_dir):
    #将文件列表复制到目标目录
    for src in src_files:
        shutil.copy(src, target_dir)

def split_data(source_dir, train_dir, valid_dir, valid_ratio=0.2):
    #划分数据到训练集和验证集
    classes = ['dog', 'cat']
    with ThreadPoolExecutor() as executor:
        for cls in classes:
            class_dir = os.path.join(source_dir, cls)
            files = [entry.path for entry in os.scandir(class_dir) if entry.is_file()]
            np.random.shuffle(files)
            split_point = int(len(files) * (1 - valid_ratio))
            train_files = files[:split_point]
            valid_files = files[split_point:]

            # 并行复制文件到训练和验证目录
            executor.submit(copy_files, train_files, os.path.join(train_dir, cls))
            executor.submit(copy_files, valid_files, os.path.join(valid_dir, cls))
# 主目录
base_dir = 'D:\\Desktop\\Datasets\\Dog_Cat'
source_dir = base_dir
train_dir = os.path.join(base_dir, 'train')
valid_dir = os.path.join(base_dir, 'valid')
# 创建目录结构并划分数据
create_train_valid_dirs(base_dir)
split_data(source_dir, train_dir, valid_dir)

4.2 训练部分设置

  1. 检查设备是否有CUDA以及导入数据集
# 检查CUDA是否可用,否则使用CPU
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(device)  # 打印出使用的设备,GPU还是CPU

# 定义训练数据的变换流程
train_transform = transforms.Compose([
    transforms.RandomResizedCrop(224),  # 随机大小、比例裁剪图像到224x224
    transforms.RandomHorizontalFlip(),  # 随机水平翻转图像
    transforms.ToTensor(),              # 将图片转换为Tensor
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 标准化处理,使用ImageNet的均值和标准差
])

# 定义验证数据的变换流程
valid_transform = transforms.Compose([
    transforms.Resize(256),             # 将图片大小调整为256x256
    transforms.CenterCrop(224),         # 中心裁剪到224x224
    transforms.ToTensor(),              # 将图片转换为Tensor
    transforms.Normalize([0.485, 0.456, 0.406], [0.229, 0.224, 0.225])  # 与训练集相同的标准化处理
])

# 加载训练数据集,并应用预定义的变换
train_dataset = datasets.ImageFolder(root=r'D:\Desktop\Datasets\Dog_Cat\train', transform=train_transform)

# 加载验证数据集,并应用预定义的变换
valid_dataset = datasets.ImageFolder(root=r'D:\Desktop\Datasets\Dog_Cat\valid', transform=valid_transform)

# 定义训练数据加载器,设置批处理大小为32,并启用随机洗牌
train_loader = DataLoader(train_dataset, batch_size=32, shuffle=True)

# 定义验证数据加载器,设置批处理大小为32,不进行洗牌
valid_loader = DataLoader(valid_dataset, batch_size=32, shuffle=False)
  1. 网络结构

第一部分卷积:
在这里插入图片描述

# 定义VGG16模型结构
class Vgg16_net(nn.Module):
    def __init__(self,num_classes= 2):
        super(Vgg16_net, self).__init__()

        # 第一层卷积层
        self.layer1 = nn.Sequential(
            # 输入3通道图像,输出64通道特征图,卷积核大小3x3,步长1,填充1
            nn.Conv2d(in_channels=3, out_channels=64, kernel_size=3, stride=1, padding=1),
            # 对64通道特征图进行Batch Normalization
            nn.BatchNorm2d(64),
            # 对64通道特征图进行ReLU激活函数
            nn.ReLU(inplace=True),
            # 输入64通道特征图,输出64通道特征图,卷积核大小3x3,步长1,填充1
            nn.Conv2d(in_channels=64, out_channels=64, kernel_size=3, stride=1, padding=1),
            # 对64通道特征图进行Batch Normalization
            nn.BatchNorm2d(64),
            # 对64通道特征图进行ReLU激活函数
            nn.ReLU(inplace=True),

            # 进行2x2的最大池化操作,步长为2
            nn.MaxPool2d(kernel_size=2, stride=2)
        )

第二部分卷积
在这里插入图片描述

        # 第二层卷积层
        self.layer2 = nn.Sequential(
            # 输入64通道特征图,输出128通道特征图,卷积核大小3x3,步长1,填充1
            nn.Conv2d(in_channels=64, out_channels=128, kernel_size=3, stride=1, padding=1),
            # 对128通道特征图进行Batch Normalization
            nn.BatchNorm2d(128),
            # 对128通道特征图进行ReLU激活函数
            nn.ReLU(inplace=True),

            # 输入128通道特征图,输出128通道特征图,卷积核大小3x3,步长1,填充1
            nn.Conv2d(in_channels=128, out_channels=128, kernel_size=3, stride=1, padding=1),
            # 对128通道特征图进行Batch Normalization
            nn.BatchNorm2d(128),
            nn.ReLU(inplace=True),
            # 进行2x2的最大池化操作,步长为2
            nn.MaxPool2d(2, 2)
        )

第三部分卷积
在这里插入图片描述

        # 第三层卷积层
        self.layer3 = nn.Sequential(
            # 输入为128通道,输出为256通道,卷积核大小为33,步长为1,填充大小为1
            nn.Conv2d(in_channels=128, out_channels=256, kernel_size=3, stride=1, padding=1),
            # 批归一化
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=256, out_channels=256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.ReLU(inplace=True),

            nn.MaxPool2d(2, 2)
        )

第四部分卷积
在这里插入图片描述

        self.layer4 = nn.Sequential(
            nn.Conv2d(in_channels=256, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.MaxPool2d(2, 2)
        )

第五部分卷积
在这里插入图片描述

        self.layer5 = nn.Sequential(
            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.Conv2d(in_channels=512, out_channels=512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.ReLU(inplace=True),

            nn.MaxPool2d(2, 2)
        )

第六部分 全连接层
在这里插入图片描述

        self.fc = nn.Sequential(
            nn.Linear(512*7*7, 512),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),

            nn.Linear(512, 256),
            nn.ReLU(inplace=True),
            nn.Dropout(0.5),

            nn.Linear(256, num_classes)
        )

forward定义

        self.conv = nn.Sequential(
            self.layer1,
            self.layer2,
            self.layer3,
            self.layer4,
            self.layer5
        )
        
    def forward(self, x):
        x = self.conv(x)
        # 对张量的拉平(flatten)操作,即将卷积层输出的张量转化为二维,全连接的输入尺寸为512
        x = x.view(x.size(0), -1)
        x = self.fc(x)
        return x
  1. 调用构建的网络,定义损失函数与优化器
model = Vgg16_net().to(device)
# 损失函数和优化器
criterion = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
  1. 训练部分,在服务器上训练,最后将图保存,需要直接显示就取消注释最后一行代码
def train_model(num_epochs,initial_weights = None):
    
    if initial_weights is not None:
        model.load_state_dict(torch.load(initial_weights))
        print(f"Loaded weights from {initial_weights}")
    
    train_losses = []
    validation_accuracies = []

    for epoch in range(num_epochs):
        model.train()
        train_loss = 0
        for images, labels in train_loader:
            images, labels = images.to(device), labels.to(device)
            optimizer.zero_grad()
            outputs = model(images)
            loss = criterion(outputs, labels)
            loss.backward()
            optimizer.step()
            train_loss += loss.item()
        
        epoch_loss = train_loss / len(train_loader)
        train_losses.append(epoch_loss)
        print(f'Epoch {epoch+1}, Train Loss: {epoch_loss}')
        torch.save(model.state_dict(), f'model_epoch_{epoch+1}.pth')
        
        # 验证模型
        model.eval()
        correct = 0
        total = 0
        with torch.no_grad():
            for images, labels in valid_loader:
                images, labels = images.to(device), labels.to(device)
                outputs = model(images)
                _, predicted = torch.max(outputs.data, 1)
                total += labels.size(0)
                correct += (predicted == labels).sum().item()
        
        accuracy = 100 * correct / total
        validation_accuracies.append(accuracy)
        print(f'Validation Accuracy: {accuracy}%')

    # 绘图
    plt.figure(figsize=(10, 5))
    plt.subplot(1, 2, 1)
    plt.plot(range(1, num_epochs + 1), train_losses, label='Train Loss')
    plt.xlabel('Epochs')
    plt.ylabel('Loss')
    plt.title('Training Loss Over Epochs')
    plt.legend()

    plt.subplot(1, 2, 2)
    plt.plot(range(1, num_epochs + 1), validation_accuracies, label='Validation Accuracy', color='r')
    plt.xlabel('Epochs')
    plt.ylabel('Accuracy (%)')
    plt.title('Validation Accuracy Over Epochs')
    plt.legend()

    plt.savefig('training_validation_metrics.png')
    # plt.show()  # 这行被注释掉,以避免在无GUI环境中尝试显示图像
# 开始训练
train_model(100)

4.3 训练结果

在这里插入图片描述

请添加图片描述结果展示了模型在100个epochs(训练周期)中的训练损失(Training Loss)和验证准确率(Validation Accuracy)的变化情况。

左图:Training Loss Over Epochs
横轴(X轴)表示训练的epochs(训练周期数),从0到100。
纵轴(Y轴)表示训练损失(Loss)。
曲线展示了训练损失随着训练周期数增加而逐渐减少的趋势。最初的训练损失大约在0.8左右,随着训练的进行,损失持续下降,到训练结束时降至接近0.2左右。
说明模型在训练过程中逐渐学习和优化,其性能在不断提高。

右图:Validation Accuracy Over Epochs
横轴(X轴)表示训练的epochs(训练周期数),从0到100。
纵轴(Y轴)表示验证准确率(Accuracy),百分比表示。
曲线展示了验证准确率随着训练周期数增加而逐渐提高的趋势。最初的验证准确率大约在50%左右,随着训练的进行,准确率不断上升,到训练结束时达到接近90%左右。
验证准确率曲线在训练初期上升较快,随后逐渐趋于平稳,最终在高水平上稍微波动。这表明模型在验证集上的表现也在逐渐提高,达到一个较高的准确率水平。

总体而言,这个训练结果表明模型的训练过程是成功的。训练损失持续下降,验证准确率持续上升,最终模型在验证集上的准确率接近90%,说明模型在图像分类任务上有很好的表现

4.4 问题分析

训练过程中损失居然上升了,可能是过拟合,或者是陷入了局部最优,并且net已经加了Dorpout。
所以,这里加上一个学习率调度器试试
在这里插入图片描述

在这里插入图片描述
可以看到,曲线平缓了很多,且损失没有大幅上升

4.5 单张图片测试

  1. 调用前面的网络构建模型,再将训练好的权重load进来,用Jupyter会显示网络架构,其他不显示也没关系
#测试模型
model_test = Vgg16_net()
model_test.load_state_dict(torch.load('model_epoch_100.pth'))
model_test.eval() 

Vgg16_net(
(layer1): Sequential(
(0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)
(layer2): Sequential(
(0): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(2): ReLU(inplace=True)
(3): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(4): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
(5): ReLU(inplace=True)
(6): MaxPool2d(kernel_size=2, stride=2, padding=0, dilation=1, ceil_mode=False)
)

  1. 图像处理
from PIL import Image

transform = transforms.Compose([
    transforms.Resize((224, 224)),  # 假设使用224x224输入
    transforms.ToTensor(),          # 将图片转换为Tensor
    transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225]),  # 归一化
])
  1. 设置图片路径,将图片读取后增加一个batch维度,因为DataLoader在获取数据时会有batch维度,之后将数据传入GPU,用模型预测类别
# 加载图片
img1 = Image.open(r'C:\Users\Administrator\Pictures\cat1.png')
img2 = Image.open(r'C:\Users\Administrator\Pictures\dog1.png')

#img2 = img2.convert('RGB')  # 确保图片是三通道的
#img.show()
# 应用预处理
img_tensor1 = transform(img1).unsqueeze(0)  # 增加批次维度
img_tensor2 = transform(img2).unsqueeze(0)  # 增加批次维度
#img_tensor.show()
# 确保使用与训练相同的设备
model_test = model_test.to(device)
img_tensor1 = img_tensor1.to(device)
img_tensor2 = img_tensor2.to(device)

# 前向传播获取输出
with torch.no_grad():
    outputs1 = model_test(img_tensor1)
    outputs2 = model_test(img_tensor2)
classes = ('cat', 'dog')

# 获取预测结果
_, predicted1 = torch.max(outputs1, 1)
_, predicted2 = torch.max(outputs2, 1)
print("Predicted class index:", classes[predicted1.item()])
print("Predicted class index:", classes[predicted2.item()])
display(img2)
  1. 测试结果
    在这里插入图片描述

5.完整训练代码与权重

在这里插入图片描述

链接:https://pan.baidu.com/s/1UW2aWyF8cRrf_tbaslJihw?pwd=18uk
提取码:18uk
–来自百度网盘超级会员V7的分享

Tips 数据集过大,这里是在3090上训练得到的权重,共训练了一天,如有需要,可以直接下载训练好的权重

参考文献

[1]深度学习12. CNN经典网络 VGG16 - 知乎
[2]VGGNet-16 Architecture: A Complete Guide
[3]pytorch-vgg16

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

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

相关文章

Accelerate 笔记:保存与加载文件

保存和加载模型、优化器、随机数生成器和 GradScaler 使用 save_state() 将上述所有内容保存到一个文件夹位置使用 load_state() 加载之前通过 save_state() 保存的状态通过使用 register_for_checkpointing(),可以注册自定义对象以便自动从前两个函数中存储或加载 …

epoll源码分析

epoll源码分析 主要数据结构epoll_create()函数实现ep_alloc():初始化结构初始化eventpoll epoll_ctl()函数实现ep_insert回调函数的实现ep_ptable_queue_proc函数ep_poll_callback epoll_wait函数SYSCALL_DEFINE4(epoll_wait, ...)ep_pollep_send_events 主要数据结…

百度/迅雷/夸克,网盘免费加速,已破!

哈喽,各位小伙伴们好,我是给大家带来各类黑科技与前沿资讯的小武。 之前给大家安利了百度网盘及迅雷的加速方法,详细方法及获取参考之前文章: 刚刚!度盘、某雷已破!速度50M/s! 本次主要介绍夸…

基于DeepLabv3+实现图像分割

目录 1. 作者介绍2. DeepLabv3算法2.1 DeepLabv3算法介绍2.2 DeepLabv3模型结构 3. 实验过程基于DeepLabv3实现图像分割3.1 VOC数据集介绍3.2 代码实现3.3 问题分析 4. 参考连接 1. 作者介绍 吴天禧,女,西安工程大学电子信息学院,2023级研究…

派派派森02

目录 1.容器 1.列表 2.元组 3.字符串 3.序列 4.集合 5.字典 2.数据容器通用操作 • max最大元素 • min最小元素 • 容器的通用转换功能 • 通用排序功能 3.字符串大小比较 4.函数中多个返回值 5.函数参数多种传递方式 1.位置参数 2.关键字参数 3.缺省参数 …

(函数)判断字符串元音字母(C语言)

一、运行结果&#xff1b; 二、源代码&#xff1b; # define _CRT_SECURE_NO_WARNINGS # include <stdio.h>//声明判断元音函数&#xff1b; void vowel(char a[100], char b[100]);int main() {//初始化变量值&#xff1b;char a[100] { 0 };char b[100] { 0 };//获取…

Python 图书馆管理系统 有GUI界面 【含Python源码 MX_031期】

使用python3&#xff0c;PyQt5&#xff0c;Sqlite3数据库搭建 数据库版本为MySQL&#xff1a;Python 图书馆管理系统&#xff08;MySQL数据库&#xff09; 有GUI界面 【含Python源码 MX_032期】-CSDN博客 主要功能&#xff1a; 用户注册、登录、修改密码、用户管理存储图书信…

Springboot校园美食推荐系统的开发-计算机毕业设计源码44555

摘要 随着人们生活水平的提高&#xff0c;人们对美食的要求也越来越高&#xff0c;对各类美食信息需求越来越大。因此&#xff0c;结合计算机快速发展、普及&#xff0c;在此基础上制作一个页面简单、美观,功能实用的校园美食推荐系统势在必行&#xff0c;满足用户分享美食的需…

【科学文献计量】使用Endnote软件打开中国知网导出的文献期刊解析不正确问题解决

使用Endnote软件打开中国知网导出的文献期刊解析不正确问题解决 问题解决问题 新建一个Endnote的材料库,然后把下载好的中国知网文献数据(知网数据导出的是Endnote格式样式)导入进来。找到文件所在路径,导入的类型选择是“Endnote import”,然后点击确定,界面结果如下 …

【Web API DOM04】事件类型、对象、解绑

一&#xff1a;事件类型 1 鼠标事件 常见鼠标事件 鼠标点击事件&#xff1a;’click‘ 鼠标移入事件&#xff1a;‘mouseenter’ 鼠标离开事件&#xff1a;‘mouseleave’ 鼠标经过事件区别 mouseover和mouseout会有冒泡效果 mouvseenter和mouseleave没有冒泡效果 2 焦…

有哪些挣钱软件一天能赚几十元?盘点十个能长期做下去的挣钱软件

在这个信息爆炸的时代&#xff0c;每个人都在寻找快速赚钱的秘诀。很多人做兼职副业的目标并不是获得很大的成功&#xff0c;大部分人一天能赚几十就心满意足了。 今天&#xff0c;我要带你一探究竟&#xff0c;揭秘那些能让你日赚几十元的挣钱软件。准备好了吗&#xff1f;让我…

vue3+typescript 使用Codemirror

安装 // npm npm install codemirror-editor-vue3 codemirror^5.65.12// ts版 还需安装&#xff1a; npm install types/codemirror全局注册 修改main.ts&#xff1a; import { createApp } from vueimport App from ./App.vueimport { InstallCodemirro } from "code…

面向对象程序设计之从C到C++的初步了解

1. C语言 1. C的发展 C是从C语言发展演变而来的&#xff0c;首先是一个更好的C引入了类的机制&#xff0c;最初的C被称为“带类的C”1983年正式取名为C 从1989年开始C语言的标准化工作 于1994年制定了ANSIC标准草案 于1998年11月被国际标准化组织(ISO)批准为国际标准&#xf…

数据结构与算法06-树结构(二叉树)

介绍 树也是基于结点的数据结构&#xff0c;但树里面的每个结点&#xff0c;可以含有多个链分别指向其他多个结点。 基于树的数据结构有很多种&#xff0c;但本章只关注其中一种——二叉树。二叉树是一种遵守以下规则的树。 每个结点的子结点数量可为 0、1、2。如果有两个子…

码蹄杯 2024 初赛第一场

MC0301 求个最大值 code: #include<bits/stdc.h> #define int long long #define endl \nusing namespace std;int n;void solve(){cin >> n;int mx -1;for(int i 0;i < n;i ){int x; cin >> x;mx max(mx,x);}cout << mx << endl; }sig…

JAVA流程控制break,continue,goto

1.break在任何循环语句的主体成分&#xff0c;均可用break控制循环的流程。break用于强行退出循环&#xff0c;不执行循环中剩余的语句。&#xff08;break语句也在switch语句中使用&#xff09; 如图&#xff1a;break语句强行退出循环&#xff0c;结果输出1~30便结束&#xf…

防火墙基础基础篇:NAT转发功能之——Easy IP方式详解

防火墙基础基础篇&#xff1a;NAT转发功能之——Easy IP方式详解 1. 概念 Easy IP 是一种简化版的动态NAPT&#xff08;Network Address and Port Translation&#xff09;技术。在Easy IP中&#xff0c;我们只使用一个公网IP地址&#xff0c;无需建立公有IP地址池。这个公网…

【数据库专家揭秘】MySql数据库设计黄金法则,让你的数据更稳定、更高效!

文章目录 引言一、明确需求&#xff0c;合理规划二、规范命名&#xff0c;提高可读性三、选择合适的数据类型四、优化表结构五、性能优化六、注重安全性总结 引言 在当今数字化时代&#xff0c;数据库已成为企业信息管理的核心。而在众多数据库系统中&#xff0c;MySql以其稳定…

jar包部署到服务器,修改jar包配置文件

jar包部署到服务器 打包项目1.jar包分离2.整体打包配置文件配置文件分离整体打包修改配置文件 打包项目 maven项目打包有两种&#xff0c;一是将自己的项目和依赖包分离&#xff0c;二是打包成一个jar包 1.jar包分离 需要在pom文件中引入依赖 <build><finalName&…

积鼎流体仿真软件VirtualFlow: 锂电池液冷散热数值计算

电池包在运作的时候会产生大量的热&#xff0c;热会在电池包内积累&#xff0c;随着车辆的使用&#xff0c;电池包内的部件会老化损伤&#xff0c;安全隐患极高&#xff0c;如何给电池包散热就显得非常重要。本文采用积鼎VirtualFlow对电芯、冷板以及冷却液进行散热仿真计算&am…