kaggle竞赛系列基于图像对水稻分类代码案例

目录

依赖环境

代码

导入依赖包

定义数据集路径:

创建训练集、验证集和测试集的文件夹:

代码的作用:

设置新的数据集路径与类别名称

代码的作用:

定义数据预处理和增强变换:

代码的作用:

定义数据集评估划分与batch大小

代码的作用:

可视化

代码的作用:

 评估可视化

代码的作用:

网络结构定义

代码的作用:

定义损失函数和优化器,并训练模型

 模型可视化评估

代码的作用:

下载地址:

python深度学习pytorch水稻图像分类完整案例


依赖环境

!pip install split-folders
!pip install torch-summary
!pip install torch matplotplib

代码

导入依赖包

import os
import pathlib
import numpy as np
import splitfolders
import itertools
import matplotlib.pyplot as plt
import torch
import torch.nn as nn
import torch.nn.functional as F
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from termcolor import colored 
from datetime import datetime
import warnings
from tqdm.notebook import tqdm
from sklearn.metrics import confusion_matrix, classification_report
from torchsummary import summary
from numpy import asarray
from PIL import Image
  • ospathlib 用于文件和目录操作。
  • numpy 用于数组和数值计算。
  • splitfolders 用于分割数据集。
  • itertools 提供迭代生成器。
  • matplotlib.pyplot 用于绘图和数据可视化。
  • torchtorch.nntorch.nn.functionaltorch.optimtorchvisiontorchvision.transforms 用于构建和训练神经网络模型。
  • termcolor 用于终端中的彩色输出。
  • datetime 用于时间操作。
  • warnings 用于忽略警告信息。
  • tqdm.notebook 用于显示进度条。
  • sklearn.metrics 提供评估指标,包括混淆矩阵和分类报告。
  • torchsummary 用于总结模型结构。
  • numpy.asarrayPIL.Image 用于图像处理。

定义数据集路径

data = './Rice_Image_Dataset'
data = pathlib.Path(data)

创建训练集、验证集和测试集的文件夹

splitfolders.ratio(input=data, output='rice_imgs', seed=42, ratio=(0.7, 0.15, 0.15))
  • 使用 splitfolders.ratio 函数将数据集按照 7:1.5:1.5 的比例划分为训练集、验证集和测试集。
  • input 参数指定输入数据集的路径。
  • output 参数指定输出文件夹的名称 'rice_imgs',划分后的数据集将保存在这个文件夹中。
  • seed 参数设置随机种子,以确保划分结果的可重复性。
  • ratio 参数指定训练集、验证集和测试集的比例,分别为 70%、15% 和 15%。

代码的作用:

这段代码通过 splitfolders 库将原始的水稻图像数据集划分为训练集、验证集和测试集,以便在模型训练、验证和测试过程中使用不同的数据子集,从而提高模型的泛化能力和评估准确性。

设置新的数据集路径与类别名称

root_dir = './rice_imgs'
root_dir = pathlib.Path(root_dir)
Arborio='./Rice_Image_Dataset/Arborio'

Arborio_classes=os.listdir(Arborio)
Rice_classes = os.listdir(root_dir)
batchsize=8

from colorama import Fore, Style

print(Fore.GREEN +str(Rice_classes))
print(Fore.YELLOW +"\nTotal number of classes are: ", len(Rice_classes))
  • root_dir 定义为之前划分后的数据集路径 './rice_imgs',并转换为路径对象。
  • Arborio 定义为原始数据集中某个类别的路径。
  • 使用 os.listdir(Arborio) 获取 Arborio 类别中的所有文件和文件夹名称。
  • 使用 os.listdir(root_dir) 获取新的数据集路径中的所有类别名称。
  • 导入 colorama 库中的 ForeStyle,用于终端输出的颜色设置。

代码的作用:

这段代码的主要作用是设置新的数据集路径,并获取数据集中各个类别的名称,以便在后续的数据加载和处理过程中使用。此外,代码还打印出了类别名称和总数,以便进行检查和验证。

定义数据预处理和增强变换

transform = transforms.Compose(
    [
        transforms.Resize((250,250)),
        transforms.ToTensor(),
        transforms.Normalize((0),(1)),
        transforms.RandomHorizontalFlip(),
        transforms.RandomRotation(30),
    ]
)
  • transforms.Compose:将多个变换操作组合在一起。
  • transforms.Resize((250,250)):将图像调整为 250x250 的固定尺寸。
  • transforms.ToTensor():将图像转换为 PyTorch 的张量格式,并将像素值归一化到 [0,1] 的范围。
  • transforms.Normalize((0),(1)):标准化图像,使图像的每个通道均值为 0,标准差为 1。
  • transforms.RandomHorizontalFlip():随机水平翻转图像,用于数据增强,以增加模型的泛化能力。
  • transforms.RandomRotation(30):随机旋转图像最多 30 度,用于数据增强。

代码的作用:

这段代码通过定义一个数据预处理和增强的变换流水线,在加载图像数据时自动对图像进行调整大小、转换为张量、标准化、随机水平翻转和随机旋转等操作。这些预处理和增强操作有助于提高模型的训练效果和泛化能力。

定义数据集评估划分与batch大小

import torch.utils.data
batch_size = 32

# Read train images as a dataset
train_set = torchvision.datasets.ImageFolder(
    os.path.join(root_dir, 'train'), transform=transform
)
# Create a Data Loader
train_loader = torch.utils.data.DataLoader(
    train_set,  batch_size = batch_size, shuffle=True
)
print(colored(f'Train Folder :\n ', 'green', attrs=['bold']))
print(train_set)
print('_'*100)

#############################################################

# Read validation images as a dataset
val_set = torchvision.datasets.ImageFolder(
    os.path.join(root_dir, 'val'), transform=transform
)
# Create a Data Loader
val_loader = torch.utils.data.DataLoader(
    val_set,  batch_size = batch_size, shuffle=True
)
print(colored(f'Validation Folder :\n ', 'red', attrs=['bold']))
print(val_set)
print('_'*100)

#############################################################

# Read test images as a dataset
test_set = torchvision.datasets.ImageFolder(
    os.path.join(root_dir, 'test'), transform=transform
)
# Create a Data Loader
test_loader = torch.utils.data.DataLoader(
    test_set,  batch_size = batch_size, shuffle=True
)
print(colored(f'Test Folder :\n ', 'yellow', attrs=['bold']))
print(test_set)
  1. 设置批量大小

    • 首先导入 torch.utils.data,并设置批量大小为 32,用于后续的数据加载器中。
  2. 加载训练集数据并创建数据加载器

    • 使用 torchvision.datasets.ImageFolder 函数加载训练集图像数据,并应用之前定义的变换 transformos.path.join(root_dir, 'train') 指定了训练集数据的路径。
    • 创建一个数据加载器 train_loader,它从 train_set 中以批量的形式读取数据,batch_size 设置为 32,并启用了随机打乱 shuffle=True
  3. 打印训练集信息

    • 使用 colored 函数将输出文本设置为绿色,并打印训练集文件夹的信息和训练集数据集对象。
  4. 加载验证集数据并创建数据加载器

    • 类似于加载训练集,使用 torchvision.datasets.ImageFolder 函数加载验证集图像数据,并应用相同的变换 transformos.path.join(root_dir, 'val') 指定了验证集数据的路径。
    • 创建一个数据加载器 val_loader,从 val_set 中以批量的形式读取数据,batch_size 设置为 32,并启用了随机打乱 shuffle=True
  5. 打印验证集信息

    • 使用 colored 函数将输出文本设置为红色,并打印验证集文件夹的信息和验证集数据集对象。
  6. 加载测试集数据并创建数据加载器

    • 类似于加载训练集和验证集,使用 torchvision.datasets.ImageFolder 函数加载测试集图像数据,并应用相同的变换 transformos.path.join(root_dir, 'test') 指定了测试集数据的路径。
    • 创建一个数据加载器 test_loader,从 test_set 中以批量的形式读取数据,batch_size 设置为 32,并启用了随机打乱 shuffle=True
  7. 打印测试集信息

    • 使用 colored 函数将输出文本设置为黄色,并打印测试集文件夹的信息和测试集数据集对象。

代码的作用:

这段代码通过加载和处理训练集、验证集和测试集的数据,创建了相应的数据加载器。这些加载器将在模型训练和评估过程中使用,以批量的形式高效地读取和处理图像数据,从而提高模型训练和评估的效率。

可视化

# 可视化数据集以进行检查
# 首先创建一个包含标签名称的字典
labels_map = {
    0: "Arborio",
    1: "Basmati",
    2: "Ipsala",
    3: "Jasmine",
    4: "Karacadag",
}

figure = plt.figure(figsize=(10, 10))
cols, rows = 5, 5
for i in range(1, cols * rows + 1):
    sample_idx = torch.randint(len(train_set), size=(1,)).item()
    img, label = train_set[sample_idx]
    figure.add_subplot(rows, cols, i)
    plt.title(labels_map[label])
    plt.axis("off")
    img_np = img.numpy().transpose((1, 2, 0))
    # 将像素值剪辑到 [0, 1] 范围内
    img_valid_range = np.clip(img_np, 0, 1)
    plt.imshow(img_valid_range)
    plt.suptitle('Rice Images', y=0.95)
plt.show()
  1. 创建标签字典

    • 创建一个字典 labels_map,将类别索引映射到类别名称,方便后续的可视化和检查。
  2. 创建可视化图形

    • 使用 plt.figure 创建一个图形对象,设置图形大小为 10x10。
    • 设置图形的列数和行数为 5,意味着将显示 25 个图像样本。
  3. 可视化图像样本

    • 使用 torch.randint 随机选择训练集中图像样本的索引。
    • train_set 中获取图像和对应的标签。
    • 将图像添加到图形的子图中,并设置子图的标题为对应的类别名称。
    • 关闭子图的坐标轴显示。
    • 将图像从张量格式转换为 NumPy 数组格式,并进行转置以匹配 plt.imshow 的输入格式。
    • 使用 np.clip 将图像的像素值限制在 [0, 1] 范围内,以确保显示的图像颜色正常。
    • 显示图像样本,并设置图形的整体标题为 "Rice Images"。

代码的作用:

这段代码通过随机选择并显示训练集中的图像样本,以及相应的类别名称,帮助检查数据是否正确加载,并提供对数据分布的直观理解。可视化的图像可以帮助确认图像增强和预处理步骤是否按照预期执行。

 评估可视化

def train(model, train_loader, validation_loader, device,
          loss_fn, optimizer, num_epochs, patience=3):
    """
    训练模型:
        model: 创建的模型
        train_loader: 使用DataLoader加载的训练集
        validation_loader: 使用DataLoader加载的验证集
        device: 训练模型可用的设备(CPU或CUDA)
        loss_fn: 定义的损失函数
        optimizer: 定义的优化器
        num_epochs (int): 训练的轮数
        patience (int): 用于早停的耐心参数
    
    """
    
    history = {
        'train_loss': [],
        'val_loss': [],
        'train_acc': [],
        'val_acc': []
    }

    epoch = 0
    best_val_loss = float('inf')
    best_model_weights = None
    early_stopping_counter = 0

    while epoch < num_epochs and early_stopping_counter < patience:
        model.train()
        train_loss = 0.0
        correct = 0
        total = 0

        pbar = tqdm(enumerate(train_loader), ncols=600, total=len(train_loader))
        for batch_idx, (inputs, labels) in pbar:
            pbar.set_description(f'Epoch {epoch+1}/{num_epochs} ')
            inputs, labels = inputs.to(device), labels.to(device)

            optimizer.zero_grad()
            outputs = model(inputs)
            loss = loss_fn(outputs, labels)
            loss.backward()
            optimizer.step()

            train_loss += loss.item()
            _, predicted = outputs.max(1)
            total += labels.size(0)
            correct += predicted.eq(labels).sum().item()

        train_loss /= len(train_loader)
        train_acc = correct / total
        history['train_loss'].append(train_loss)
        history['train_acc'].append(train_acc)

        val_loss, val_acc = evaluate(model, validation_loader, device, loss_fn)
        history['val_loss'].append(val_loss)
        history['val_acc'].append(val_acc)

        # 打印进度
        print(f'train_loss: {train_loss:.4f} | '
              f'train_acc: {train_acc:.4f} | ' +
              f'val_loss: {val_loss:.4f} | ' +
              f'val_acc: {val_acc:.4f}', '\n')

        if history['val_loss'][-1] < best_val_loss:
            best_model_weights = model.state_dict()
            early_stopping_counter = 0
        else:
            early_stopping_counter += 1
            
        best_val_loss = history['val_loss'][-1]
        epoch += 1

    return history, best_model_weights

# ---------------------------------------------------------------

def evaluate(model, data_loader, device, loss_fn):
    """
    评估模型并返回损失和准确率:
        model: 创建的模型
        data_loader: 测试或验证集加载器
        device: 训练模型可用的设备(CPU或CUDA)
        loss_fn: 定义的损失函数
    """

    model.eval()
    total_loss = 0.0
    correct = 0
    total = 0

    with torch.no_grad():
        for inputs, labels in data_loader:
            inputs, labels = inputs.to(device), labels.to(device)

            outputs = model(inputs)
            loss = loss_fn(outputs, labels)
            total_loss += loss.item()

            _, predicted = outputs.max(1)
            total += labels.size(0)
            correct += predicted.eq(labels).sum().item()

    val_loss = total_loss / len(data_loader)
    val_acc = correct / total

    return val_loss, val_acc

# -------------------------------------------------------------------

def plot_comparision_result(model):
    """
    绘制训练和验证集准确率和损失的对比图:
        model: 创建的模型
    """
    
    fig, axs = plt.subplots(2, 1, figsize=(10, 12))
    
    # 绘制训练和验证集的准确率
    axs[0].plot(model['history']['train_acc'], color="red", marker="o")
    axs[0].plot(model['history']['val_acc'], color="blue", marker="h")
    axs[0].set_title('训练集和验证集准确率对比')
    axs[0].set_ylabel('准确率')
    axs[0].set_xlabel('轮次')
    axs[0].legend(['训练集', '验证集'], loc="lower right")
    
    # 绘制训练和验证集的损失
    axs[1].plot(model['history']['train_loss'], color="red", marker="o")
    axs[1].plot(model['history']['val_loss'], color="blue", marker="h")
    axs[1].set_title('训练集和验证集损失对比')
    axs[1].set_ylabel('损失')
    axs[1].set_xlabel('轮次')
    axs[1].legend(['训练集', '验证集'], loc="upper right")

    plt.tight_layout()
    plt.show()

# -------------------------------------------------------------------

# 定义函数以创建包含实际标签和预测标签的两个列表
def get_ture_and_pred_labels(dataloader, model):
    """
    获取包含实际标签和预测标签的两个列表,用于混淆矩阵:
        dataloader: 数据加载器
        model: 创建的模型
    """
    i = 0
    y_true = []
    y_pred = []
    for images, labels in dataloader:
        images = images.to(device)
        labels = labels.numpy()
        outputs = model(images)
        _, pred = torch.max(outputs.data, 1)
        pred = pred.detach().cpu().numpy()
        
        y_true = np.append(y_true, labels)
        y_pred = np.append(y_pred, pred)
    
    return y_true, y_pred

# ------------------------------------------------------------------

def plot_confusion_matrix(cm, classes,
                          title='Confusion matrix',
                          cmap=plt.cm.Blues):
    """
    绘制混淆矩阵:
        cm(array): 混淆矩阵
        classes(dictionary): 目标类别(key=分类类型,value=数值类型)
    """
    plt.figure(figsize=(10,7))
    plt.grid(False)
    plt.imshow(cm, interpolation='nearest', cmap=cmap)
    plt.title(title)
    plt.colorbar()
    tick_marks = np.arange(len(classes))

    plt.xticks(tick_marks, [f"{value}={key}" for key , value in classes.items()], rotation=45)
    plt.yticks(tick_marks, [f"{value}={key}" for key , value in classes.items()])

    thresh = cm.max() / 2.
    for i, j in itertools.product(range(cm.shape[0]), range(cm.shape[1])):
        plt.text(j, i, f"{cm[i,j]}\n{cm[i,j]/np.sum(cm)*100:.2f}%",
                 horizontalalignment="center",
                 color="white" if cm[i, j] > thresh else "black")

    
    plt.ylabel('实际值')
    plt.xlabel('预测值')
    plt.tight_layout()
    plt.show()

代码的作用:

  1. train 函数

    • 训练模型并记录训练和验证集的损失和准确率。
    • 实现早停机制以防止过拟合。
  2. evaluate 函数

    • 评估模型在给定数据集上的表现,返回损失和准确率。
  3. plot_comparision_result 函数

    • 绘制训练和验证集的准确率和损失随训练轮次变化的对比图。
  4. get_ture_and_pred_labels 函数

    • 获取实际标签和预测标签的列表,用于计算混淆矩阵。
  5. plot_confusion_matrix 函数

    • 绘制混淆矩阵以评估分类模型的性能,显示分类结果的准确性。

网络结构定义

# 定义第二个卷积神经网络模型:包含两个卷积层和两个池化层
class Model(nn.Module):
    def __init__(self, dim_output):
        super().__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)  # 第一个卷积层,输入通道数为3(RGB图像),输出通道数为6,卷积核大小为5x5
        self.pool = nn.MaxPool2d(2, 2)  # 最大池化层,窗口大小为2x2
        self.conv2 = nn.Conv2d(6, 16, 5)  # 第二个卷积层,输入通道数为6,输出通道数为16,卷积核大小为5x5
        self.fc1 = nn.Linear(16 * 59 * 59, 120)  # 第一个全连接层,输入维度为16*59*59,输出维度为120
        self.fc2 = nn.Linear(120, 84)  # 第二个全连接层,输入维度为120,输出维度为84
        self.fc3 = nn.Linear(84, dim_output)  # 第三个全连接层,输入维度为84,输出维度为类别数

    def forward(self, x):
        x = self.pool(F.relu(self.conv1(x)))  # 第一个卷积层后接ReLU激活函数和池化层
        x = self.pool(F.relu(self.conv2(x)))  # 第二个卷积层后接ReLU激活函数和池化层
        x = torch.flatten(x, 1)  # 展平操作,展平所有维度除了批量维度
        x = F.relu(self.fc1(x))  # 第一个全连接层后接ReLU激活函数
        x = F.relu(self.fc2(x))  # 第二个全连接层后接ReLU激活函数
        x = self.fc3(x)  # 第三个全连接层
        return x

model_ = Model(5)  # 实例化模型,类别数为5

summary(model_, (3, 250, 250))  # 打印模型结构和参数信息,输入图像尺寸为3x250x250
  1. 定义卷积神经网络模型

    • __init__ 方法中定义了两个卷积层、两个池化层和三个全连接层。
    • conv1:第一个卷积层,输入通道数为3,输出通道数为6,卷积核大小为5x5。
    • pool:最大池化层,窗口大小为2x2。
    • conv2:第二个卷积层,输入通道数为6,输出通道数为16,卷积核大小为5x5。
    • fc1:第一个全连接层,输入维度为165959,输出维度为120。
    • fc2:第二个全连接层,输入维度为120,输出维度为84。
    • fc3:第三个全连接层,输入维度为84,输出维度为类别数(即输出维度)。
  2. 定义前向传播

    • forward 方法定义了前向传播过程。
    • 输入图像依次通过卷积层、激活函数、池化层、展平操作和全连接层。
    • 最后输出的结果用于分类任务。
  3. 实例化模型

    • model_ = Model(5):实例化模型,类别数为5。
  4. 显示模型结构和参数信息

    • summary(model_, (3, 250, 250)):使用 torchsummary 显示模型的结构和参数信息,输入图像尺寸为3x250x250。

代码的作用:

这段代码定义了一个用于图像分类的卷积神经网络模型,并显示了模型的结构和参数信息。这有助于了解模型的层次结构和参数量,为后续的模型训练和评估做准备。

定义损失函数和优化器,并训练模型

# define a Loss function and optimizer for model_2
loss_fn = nn.CrossEntropyLoss()
optimizer = optim.Adam(model_.parameters(), lr=0.001)

# train model_
history_2, best_model_weights_2 = train(model_, train_loader, val_loader,
                                        device, loss_fn, optimizer, num_epochs=5, patience=5)

 模型可视化评估

size_histories = {}

# 存储训练结果
size_histories['Model_'] = {'history': history_2, 'weights': best_model_weights_2}

# 绘制模型在每个训练轮次的准确率和损失图
plot_comparision_result(size_histories['Model_'])

# 检查混淆矩阵进行错误分析
y_true, y_pred = get_ture_and_pred_labels(val_loader, model_)

print(classification_report(y_true, y_pred), '\n\n')
cm = confusion_matrix(y_true, y_pred)

classes = {
    "Arborio": 0,
    "Basmati": 1,
    "Ipsala": 2,
    "Jasmine": 3,
    "Karacadag": 4,
}

plot_confusion_matrix(cm, classes, title='Confusion matrix', cmap=plt.cm.Blues)
  • 存储训练结果

    • 初始化一个字典 size_histories 用于存储不同模型的训练结果。
    • Model_ 模型的训练历史记录和最佳模型权重存储在 size_histories['Model_'] 中。
  • 绘制模型的准确率和损失图

    • 调用 plot_comparision_result 函数,绘制模型在每个训练轮次的准确率和损失图。该函数将绘制训练集和验证集的准确率和损失随训练轮次变化的对比图,以便直观地评估模型的性能。
  • 检查混淆矩阵进行错误分析

    • 使用 get_ture_and_pred_labels 函数获取验证集中真实标签和预测标签的列表 y_truey_pred
    • 打印分类报告 classification_report(y_true, y_pred),显示每个类别的精度、召回率和F1分数。
    • 计算混淆矩阵 cm,显示模型在验证集上的分类错误情况。
    • 定义类别名称和对应的数值标签字典 classes
    • 调用 plot_confusion_matrix 函数,绘制混淆矩阵图,显示各类别的分类结果。

代码的作用:

这段代码将模型的训练结果进行存储,并通过绘制准确率和损失图帮助评估模型在训练过程中的表现。通过分类报告和混淆矩阵,可以详细分析模型在验证集上的分类效果,识别模型在不同类别上的分类准确性以及存在的错误,从而为模型的优化提供依据。这种详细的错误分析对于提高模型的性能和泛化能力具有重要意义。

 

 

下载地址:

python深度学习pytorch水稻图像分类完整案例

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

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

相关文章

Appium自动化环境搭建保姆级教程

APP自动化测试运行环境比较复杂&#xff0c;稍微不注意安装就会失败。我见过不少朋友&#xff0c;装了1个星期&#xff0c;Appium 的运行环境还没有搭好的。 搭建环境本身不是一个有难度的工作&#xff0c;但是 Appium 安装过程中确实存在不少隐藏的比较深的坑&#xff0c;如果…

kafka-集群搭建(在docker中搭建)

文章目录 1、kafka集群搭建1.1、下载镜像文件1.2、创建zookeeper容器并运行1.3、创建3个kafka容器并运行1.3.1、9095端口1.3.2、9096端口1.3.3、9097端口 1.4、重启kafka-eagle1.5、查看 efak1.5.1、查看 brokers1.5.2、查看 zookeeper 1、kafka集群搭建 1.1、下载镜像文件 d…

Vuforia AR篇(五)— 地平面检测

目录 前言一、什么是地平面识别&#xff1f;二、使用步骤三、示例代码四、效果五、总结 前言 在增强现实&#xff08;AR&#xff09;应用程序的开发中&#xff0c;地平面识别是一项关键技术&#xff0c;它允许虚拟对象与现实世界的地面进行互动。Vuforia 是一个功能强大的 AR …

javacv ffmpeg使用笔记 (补充中...)

javacv ffmpeg使用笔记 一、maven依赖二、示例代码1. 获取视频时长 三、小技巧 一、maven依赖 使用javacv ffmpeg并指定classifier之后&#xff0c;就不需要额外安装ffmpeg软件&#xff08;jar包中已经内置&#xff09;了。 全量依赖包&#xff08;不推荐&#xff09;安装包总大…

6、架构-服务端缓存

为系统引入缓存之前&#xff0c;第一件事情是确认系统是否真的需要缓 存。从开发角度来说&#xff0c;引入缓存会提 高系统复杂度&#xff0c;因为你要考虑缓存的失效、更新、一致性等问题&#xff1b;从运维角度来说&#xff0c;缓存会掩盖一些缺 陷&#xff0c;让问题在更久的…

HashMap的get和put方法

在 JDK 1.8 中&#xff0c;HashMap 是一个常用的实现了 Map 接口的哈希表&#xff0c;它允许存储键值对&#xff0c;并且键和值都可以为 null。HashMap 的主要特点是其基于哈希表的实现&#xff0c;提供了快速的查找和插入操作。以下是 HashMap 中 get 和 put 方法的介绍及其实…

Flink状态State | 大数据技术

⭐简单说两句⭐ ✨ 正在努力的小叮当~ &#x1f496; 超级爱分享&#xff0c;分享各种有趣干货&#xff01; &#x1f469;‍&#x1f4bb; 提供&#xff1a;模拟面试 | 简历诊断 | 独家简历模板 &#x1f308; 感谢关注&#xff0c;关注了你就是我的超级粉丝啦&#xff01; &a…

使用J-LINK COMMANDER检查极海APM32F072烧录

键入 connect: 此时会显示默认设备&#xff0c;如果之前设置过会有&#xff0c;为了演示&#xff0c;我不选 键入 &#xff1f; 然后会弹出设备选择界面&#xff1a; 根据自己的设备搜索型号&#xff1a; 我这里搜索“APM32F072VB”,点击OK: 选择接口类型&#xff1a; 如果要…

用Python优雅地写LaTeX

latexify用于生成 LaTeX 数学公式的 Python 库。LaTeX 是一种基于 ΤΕΧ 的排版系统&#xff0c;对于展示复杂的数学公式表现极为出色。该项目可以用 Python 函数&#xff0c;轻松生成复杂的 LaTeX 数学公式描述。 安装库 查看版本号 0.4.2 案例演示 我们需要以装饰器的形式…

jquery发ajax自动302、xhrredirect,莫名弹出登录窗口。tomcat部署情况下

效果如下&#xff1a; 原因如下&#xff1a; 跟tomcat自带的一个项目同名了&#xff0c;只要前缀跟那个项目同名 都被拦截。 解决方案&#xff1a; 我直接改了一个接口名字&#xff0c;只要不和tomcat自带项目名字一样即可

Linux基础 (十二):Linux 线程的创建与同步

本篇博客详细介绍与线程有关的内容&#xff0c;这部分也是笔试面试的重点&#xff0c;需要我们对线程有深刻的理解&#xff0c;尤其是线程的并发运行以及线程同步的控制&#xff01;接下来&#xff0c;让我们走进线程的世界&#xff0c;去理解线程&#xff0c;使用线程&#xf…

RocketMQ学习(3) 秒杀实战

学习完RocketMQ的用法,现在用它来做一个简单的秒杀项目练练手。 关于秒杀,我之前其实有专门的学习过其中的一些业务逻辑和常见问题,我在这篇博客中有写过多并发场景下的秒杀场景,需要考虑哪些问题?也可以学习一下 除了RocketMQ,本文还需要会springBoot + Redis + Mysql…

隐藏 IP 地址的重要性是什么?

在当今的数字时代&#xff0c;保护我们的在线身份至关重要。从保护个人信息到保护隐私&#xff0c;互联网用户越来越多地寻求增强在线安全性的方法。保持匿名和保护敏感数据的一个关键方面是隐藏您的 IP 地址。在这篇博文中&#xff0c;我们将深入探讨隐藏 IP 地址的重要性&…

项目:消息队列的前置知识

文章目录 写在前面环境安装 Protubuf基本介绍 Muduo基本介绍 SQLite3异步操作实现线程池 本篇是对于一个仿RabbitMQ实现的消息队列项目的前置知识的说明文档 写在前面 环境安装 Protubuf 基本介绍 项目所需要的比较重要模块有Protubuf模块&#xff0c;那么下面先对于这个模…

28 _ WebComponent:像搭积木一样构建Web应用

在上一篇文章中我们从技术演变的角度介绍了PWA&#xff0c;这是一套集合了多种技术的理念&#xff0c;让浏览器渐进式适应设备端。今天我们要站在开发者和项目角度来聊聊WebComponent&#xff0c;同样它也是一套技术的组合&#xff0c;能提供给开发者组件化开发的能力。 那什么…

微信支付(可复用)

3.1微信支付 本项目选择小程序支付 参考&#xff1a;产品中心 - 微信支付商户平台微信支付商户平台提供各类支付产品满足商家通过微信支付收款的需求&#xff1b;平台提供智慧经营&#xff0c;现金红包&#xff0c;代金券等运营工具&#xff0c;助力商家更好的玩转营销&#x…

重生奇迹mu格斗家介绍

出生地&#xff1a;勇者大陆 性 别&#xff1a;男 擅 长&#xff1a;近距离攻击、技能以PVP为主战斗风格 转 职&#xff1a;格斗大师&#xff08;3转&#xff09; 介 绍&#xff1a;以PVP战斗模式为主的格斗家&#xff0c;依角色养成配点不同&#xff0c;可发展成以力量体力…

恒创科技:无法与服务器建立安全连接怎么解决?

在使用互联网服务时&#xff0c;有时会出现无法与服务器建立安全连接的问题&#xff0c;此错误消息通常出现在尝试访问需要安全连接的网站(例如使用 HTTPS 的网站)时&#xff0c;这可能是由于多种原因造成的&#xff0c;以下是一些常见的解决方法&#xff0c;帮助你解决问题。 …

AI来了,产品经理该怎样面对它?

AI终于来了&#xff0c;我们一方面期待着它可能给我们生活带来的变化&#xff0c;另一方面又担忧它可能带给我们巨大的风险和挑战。 AI带来的影响 AI不确定性的风险有很多&#xff0c;例如有人关注它是否成为“奥创”&#xff0c;但对我们大多数人来说这样的风险还很遥远&#…

Java1.8+ idea hbuilder+ uniapp、vue上门家政小程序APP源码开发

Java1.8 idea hbuilder uniapp、vue上门家政小程序APP源码开发 家政服务系统是一种专为家庭提供全方位服务的综合性系统。该系统通过整合多种服务功能和智能化管理&#xff0c;旨在提高家庭生活的质量和效率。 家政服务系统技术开发环境&#xff1a; 技术架构&#xff1a;spri…