基于MNIST数据集的手写数字识别(CNN)

news2025/5/17 15:06:34

目录

一,模型训练

1.1 数据集介绍

1.2 CNN模型层结构

1.3 定义CNN模型

1.4 神经网络的前向传播过程

1.5 数据预处理

1.6 加载数据

1.7 初始化

1.8 模型训练过程

1.9 保存模型

二,模型测试

2.1 定义与训练时相同的CNN模型架构

2.2 图像的预处理

2.3 预测

三,测试

3.1 测试方法

3.2 测试结果

四 ,总结

五,完整代码

5.1 模型训练部分代码

5.2 模型测试部分代码


本实验直观地体现了CNN对比全连接对于图像处理的优势

全连接网络实现MNIST数字识别实验如下链接:

基于MNIST数据集的手写数字识别(简单全连接网络)-CSDN博客


一,模型训练

1.1 数据集介绍

        MNIST 数据集由 60,000 张图像构成的训练集和 10,000 张图像组成的测试集构成,其中的图像均为 28×28 像素的灰度图,涵盖 0 - 9 这 10 个阿拉伯数字,且数字书写风格、大小、位置多样。它源于美国国家标准与技术研究所(NIST)的数据集,经过归一化和中心化处理。MNIST 数据集是图像识别研究领域的经典数据集,常用于开发和评估图像识别算法与模型,也是机器学习课程中常用的教学案例,许多高性能卷积神经网络模型在该数据集测试集上准确率可达 99% 以上,充分展现出其在机器学习领域的重要价值和广泛应用。

1.2 CNN模型层结构

1.3 定义CNN模型

def __init__(self):
        super(CNN, self).__init__()  # 调用父类的初始化方法
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 定义第一个卷积层,输入通道1,输出通道32,卷积核大小3x3
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)  # 定义第二个卷积层,输入通道32,输出通道64,卷积核大小3x3
        self.pool = nn.MaxPool2d(2, 2)  # 定义最大池化层,池化核大小2x2
        self.dropout1 = nn.Dropout2d(0.25)  # 定义第一个Dropout层,随机丢弃25%的神经元
        self.fc1 = nn.Linear(64 * 12 * 12, 128)  # 定义第一个全连接层,输入维度64*12*12,输出维度128
        self.dropout2 = nn.Dropout(0.5)  # 定义第二个Dropout层,随机丢弃50%的神经元
        self.fc2 = nn.Linear(128, 10)  # 定义输出层,输入维度128,输出维度10(对应10个数字类别)

        定义了一个用于手写数字识别的卷积神经网络(CNN)架构,专为 MNIST 等单通道图像分类任务设计。网络包含两个卷积层(Conv1 和 Conv2)进行特征提取,每个卷积层后接 ReLU 激活函数和最大池化层(MaxPool2d)进行下采样,逐步将 28×28 的输入图像转换为更高层次的抽象特征。为防止过拟合,在卷积层后添加了 Dropout2d (0.25),在全连接层前使用 Dropout (0.5) 增强模型泛化能力。特征提取完成后,通过两次全连接层(FC1 和 FC2)将卷积输出的多维特征映射到 10 个类别,最终输出对应 0-9 数字的分类得分。

1.4 神经网络的前向传播过程

    def forward(self, x):
        # 第一层卷积+ReLU激活
        x = torch.relu(self.conv1(x))
        # 第二层卷积+ReLU激活+池化
        x = self.pool(torch.relu(self.conv2(x)))
        # 应用Dropout
        x = self.dropout1(x)
        # 将多维张量展平为一维向量(64*12*12)
        x = x.view(-1, 64 * 12 * 12)
        # 第一个全连接层+ReLU激活
        x = torch.relu(self.fc1(x))
        # 应用Dropout
        x = self.dropout2(x)
        # 输出层,得到未归一化的预测分数
        x = self.fc2(x)
        return x

1.5 数据预处理

transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为张量
    transforms.Normalize((0.1307,), (0.3081,))  # 使用MNIST数据集的均值和标准差进行归一化
])

1.6 加载数据

train_dataset = datasets.MNIST('data', train=True, download=True, transform=transform)  # 加载MNIST训练数据集
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)  # 创建数据加载器,批次大小为64,打乱数据

1.7 初始化

model = CNN()  # 创建CNN模型实例
criterion = nn.CrossEntropyLoss()  # 定义交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 定义Adam优化器,学习率为0.001

1.8 模型训练过程

def train(epochs):
    model.train()  # 设置模型为训练模式
    for epoch in range(epochs):  # 进行指定轮数的训练
        running_loss = 0.0  # 初始化本轮的损失累加器
        for batch_idx, (data, target) in enumerate(train_loader):  # 遍历数据加载器中的每个批次
            optimizer.zero_grad()  # 梯度清零
            output = model(data)  # 前向传播,计算模型输出
            loss = criterion(output, target)  # 计算损失
            loss.backward()  # 反向传播,计算梯度
            optimizer.step()  # 更新模型参数
            running_loss += loss.item()  # 累加当前批次的损失

            if batch_idx % 100 == 0:  # 每100个批次打印一次损失
                print(f'Epoch {epoch + 1}, Batch {batch_idx}, Loss: {loss.item():.6f}')

        print(f'Epoch {epoch + 1} completed, Average Loss: {running_loss / len(train_loader):.6f}')  # 打印本轮平均损失

1.9 保存模型

if __name__ == '__main__':
    train(epochs=5)  # 调用训练函数,训练5轮
    torch.save(model.state_dict(),'mnist_cnn_model.pth')  # 保存模型的参数
    print("模型已保存为: mnist_cnn_model.pth")  # 打印保存模型的信息

二,模型测试

2.1 定义与训练时相同的CNN模型架构

class CNN(nn.Module):
    def __init__(self):
        # 调用父类初始化方法
        super(CNN, self).__init__()
        # 第一个卷积层:输入1通道(灰度图),输出32通道,卷积核3x3
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
        # 第二个卷积层:输入32通道,输出64通道,卷积核3x3
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
        # 最大池化层:核大小2x2,步长2
        self.pool = nn.MaxPool2d(2, 2)
        # Dropout层:训练时随机丢弃25%的神经元,防止过拟合
        self.dropout1 = nn.Dropout2d(0.25)
        # 第一个全连接层:输入维度64*12*12,输出128
        self.fc1 = nn.Linear(64 * 12 * 12, 128)
        # Dropout层:训练时随机丢弃50%的神经元
        self.dropout2 = nn.Dropout(0.5)
        # 输出层:输入128,输出10个类别(对应0-9数字)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        # 第一层卷积+ReLU激活
        x = torch.relu(self.conv1(x))
        # 第二层卷积+ReLU激活+池化
        x = self.pool(torch.relu(self.conv2(x)))
        # 应用Dropout
        x = self.dropout1(x)
        # 将多维张量展平为一维向量(64*12*12)
        x = x.view(-1, 64 * 12 * 12)
        # 第一个全连接层+ReLU激活
        x = torch.relu(self.fc1(x))
        # 应用Dropout
        x = self.dropout2(x)
        # 输出层,得到未归一化的预测分数
        x = self.fc2(x)
        return x

2.2 图像的预处理

def preprocess_image(image_path):
    """预处理自定义图像,使其符合模型输入要求"""
    # 打开图像并转换为灰度图(单通道)
    image = Image.open(image_path).convert('L')

    # 调整图像大小为28x28像素(如果不是)
    if image.size != (28, 28):
        image = image.resize((28, 28), Image.Resampling.LANCZOS)

    # 将PIL图像转换为numpy数组以便处理
    img_array = np.array(image)

    # 预处理:二值化和颜色反转
    # MNIST数据集中数字为白色(255),背景为黑色(0)
    if img_array.mean() > 127:  # 如果平均像素值大于127,说明可能是黑底白字
        img_array = 255 - img_array  # 颜色反转

    # 将numpy数组转换为PyTorch张量并添加批次维度
    img_tensor = transforms.ToTensor()(img_array).unsqueeze(0)
    # 使用MNIST数据集的均值和标准差进行归一化
    img_tensor = transforms.Normalize((0.1307,), (0.3081,))(img_tensor)

    return image, img_tensor  # 返回原始图像和处理后的张量

2.3 预测

def predict_digit(image_path):
    """预测自定义图像中的数字"""
    # 创建模型实例
    model = CNN()
    # 加载预训练模型权重
    model.load_state_dict(torch.load('mnist_cnn_model.pth'))
    # 设置模型为评估模式(关闭Dropout等训练特有的层)
    model.eval()

    # 预处理输入图像
    original_img, img_tensor = preprocess_image(image_path)

    # 预测过程,不计算梯度以提高效率
    with torch.no_grad():
        # 前向传播,得到模型输出
        output = model(img_tensor)
        # 应用softmax将输出转换为概率分布
        probabilities = torch.softmax(output, dim=1)
        # 获取最高概率及其对应的数字类别
        confidence, predicted = torch.max(probabilities, 1)

三,测试

3.1 测试方法

如上文代码所示,我这里用的测试图片是自己定义图片,使用电脑自带的paint绘图软件,设置画布为28*28像素,黑底白字,手动写入一个字进行预测

3.2 测试结果

        预测5的置信度为99.94%

        预测0的置信度为99.99%

        预测7的置信度为92.33%(尽管这个“7”写的很不好但是并不影响预测结果)


四 ,总结

        卷积神经网络(CNN)在图像分类中相比全连接网络(FNN)具有显著优势:通过局部连接权重共享机制,CNN 大幅减少参数量,避免全连接网络因输入维度高导致的参数爆炸问题,计算效率更高且不易过拟合;CNN 通过卷积核逐层提取图像的局部特征(如边缘、纹理),结合池化层的平移不变性,能自动学习从低级到高级的层级化语义特征,而全连接网络将图像展平为向量,完全忽略像素空间关系,需依赖人工特征或大量数据学习;此外,CNN 的卷积结构天然具备正则化效果,对数据量需求更低,训练速度更快,且通过可视化卷积核和特征图可直观解释其对图像模式的捕捉过程,而全连接网络的特征表示缺乏可解释性。


五,完整代码

5.1 模型训练部分代码

import torch  # 导入PyTorch库,用于深度学习
import torch.nn as nn  # 导入PyTorch的神经网络模块
import torch.optim as optim  # 导入PyTorch的优化器模块
from torchvision import datasets, transforms  # 从torchvision导入数据集和数据变换模块
from torch.utils.data import DataLoader  # 导入数据加载器模块

# 定义CNN模型
class CNN(nn.Module):
    def __init__(self):
        super(CNN, self).__init__()  # 调用父类的初始化方法
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)  # 定义第一个卷积层,输入通道1,输出通道32,卷积核大小3x3
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)  # 定义第二个卷积层,输入通道32,输出通道64,卷积核大小3x3
        self.pool = nn.MaxPool2d(2, 2)  # 定义最大池化层,池化核大小2x2
        self.dropout1 = nn.Dropout2d(0.25)  # 定义第一个Dropout层,随机丢弃25%的神经元
        self.fc1 = nn.Linear(64 * 12 * 12, 128)  # 定义第一个全连接层,输入维度64*12*12,输出维度128
        self.dropout2 = nn.Dropout(0.5)  # 定义第二个Dropout层,随机丢弃50%的神经元
        self.fc2 = nn.Linear(128, 10)  # 定义输出层,输入维度128,输出维度10(对应10个数字类别)

    def forward(self, x):
        x = torch.relu(self.conv1(x))  # 对第一个卷积层的输出应用ReLU激活函数
        x = self.pool(torch.relu(self.conv2(x)))  # 对第二个卷积层的输出应用ReLU激活函数,然后进行最大池化
        x = self.dropout1(x)  # 应用第一个Dropout层
        x = x.view(-1, 64 * 12 * 12)  # 将张量展平为一维向量,-1表示自动推断批次维度
        x = torch.relu(self.fc1(x))  # 对第一个全连接层的输出应用ReLU激活函数
        x = self.dropout2(x)  # 应用第二个Dropout层
        x = self.fc2(x)  # 通过输出层
        return x  # 返回模型的输出

# 数据预处理
transform = transforms.Compose([
    transforms.ToTensor(),  # 将图像转换为张量
    transforms.Normalize((0.1307,), (0.3081,))  # 使用MNIST数据集的均值和标准差进行归一化
])

# 加载数据
train_dataset = datasets.MNIST('data', train=True, download=True, transform=transform)  # 加载MNIST训练数据集
train_loader = DataLoader(train_dataset, batch_size=64, shuffle=True)  # 创建数据加载器,批次大小为64,打乱数据

# 初始化模型、损失函数和优化器
model = CNN()  # 创建CNN模型实例
criterion = nn.CrossEntropyLoss()  # 定义交叉熵损失函数
optimizer = optim.Adam(model.parameters(), lr=0.001)  # 定义Adam优化器,学习率为0.001

# 训练模型
def train(epochs):
    model.train()  # 设置模型为训练模式
    for epoch in range(epochs):  # 进行指定轮数的训练
        running_loss = 0.0  # 初始化本轮的损失累加器
        for batch_idx, (data, target) in enumerate(train_loader):  # 遍历数据加载器中的每个批次
            optimizer.zero_grad()  # 梯度清零
            output = model(data)  # 前向传播,计算模型输出
            loss = criterion(output, target)  # 计算损失
            loss.backward()  # 反向传播,计算梯度
            optimizer.step()  # 更新模型参数
            running_loss += loss.item()  # 累加当前批次的损失

            if batch_idx % 100 == 0:  # 每100个批次打印一次损失
                print(f'Epoch {epoch + 1}, Batch {batch_idx}, Loss: {loss.item():.6f}')

        print(f'Epoch {epoch + 1} completed, Average Loss: {running_loss / len(train_loader):.6f}')  # 打印本轮平均损失

# 执行训练并保存模型
if __name__ == '__main__':
    train(epochs=5)  # 调用训练函数,训练5轮
    torch.save(model.state_dict(),'mnist_cnn_model.pth')  # 保存模型的参数
    print("模型已保存为: mnist_cnn_model.pth")  # 打印保存模型的信息

5.2 模型测试部分代码

# 导入PyTorch深度学习框架及其神经网络模块
import torch
import torch.nn as nn
# 导入torchvision的图像变换工具
from torchvision import transforms
# 导入PIL库用于图像处理
from PIL import Image
# 导入matplotlib用于可视化
import matplotlib.pyplot as plt
# 导入numpy用于数值计算
import numpy as np
# 导入os模块用于文件和路径操作
import os

# 设置matplotlib的字体,确保中文正常显示
plt.rcParams['font.sans-serif'] = ['SimHei', 'WenQuanYi Micro Hei', 'Heiti TC']
plt.rcParams['axes.unicode_minus'] = False  # 解决负号显示问题


# 定义与训练时相同的CNN模型架构
class CNN(nn.Module):
    def __init__(self):
        # 调用父类初始化方法
        super(CNN, self).__init__()
        # 第一个卷积层:输入1通道(灰度图),输出32通道,卷积核3x3
        self.conv1 = nn.Conv2d(1, 32, kernel_size=3)
        # 第二个卷积层:输入32通道,输出64通道,卷积核3x3
        self.conv2 = nn.Conv2d(32, 64, kernel_size=3)
        # 最大池化层:核大小2x2,步长2
        self.pool = nn.MaxPool2d(2, 2)
        # Dropout层:训练时随机丢弃25%的神经元,防止过拟合
        self.dropout1 = nn.Dropout2d(0.25)
        # 第一个全连接层:输入维度64*12*12,输出128
        self.fc1 = nn.Linear(64 * 12 * 12, 128)
        # Dropout层:训练时随机丢弃50%的神经元
        self.dropout2 = nn.Dropout(0.5)
        # 输出层:输入128,输出10个类别(对应0-9数字)
        self.fc2 = nn.Linear(128, 10)

    def forward(self, x):
        # 第一层卷积+ReLU激活
        x = torch.relu(self.conv1(x))
        # 第二层卷积+ReLU激活+池化
        x = self.pool(torch.relu(self.conv2(x)))
        # 应用Dropout
        x = self.dropout1(x)
        # 将多维张量展平为一维向量(64*12*12)
        x = x.view(-1, 64 * 12 * 12)
        # 第一个全连接层+ReLU激活
        x = torch.relu(self.fc1(x))
        # 应用Dropout
        x = self.dropout2(x)
        # 输出层,得到未归一化的预测分数
        x = self.fc2(x)
        return x


def preprocess_image(image_path):
    """预处理自定义图像,使其符合模型输入要求"""
    # 打开图像并转换为灰度图(单通道)
    image = Image.open(image_path).convert('L')

    # 调整图像大小为28x28像素(如果不是)
    if image.size != (28, 28):
        image = image.resize((28, 28), Image.Resampling.LANCZOS)

    # 将PIL图像转换为numpy数组以便处理
    img_array = np.array(image)

    # 预处理:二值化和颜色反转
    # MNIST数据集中数字为白色(255),背景为黑色(0)
    if img_array.mean() > 127:  # 如果平均像素值大于127,说明可能是黑底白字
        img_array = 255 - img_array  # 颜色反转

    # 将numpy数组转换为PyTorch张量并添加批次维度
    img_tensor = transforms.ToTensor()(img_array).unsqueeze(0)
    # 使用MNIST数据集的均值和标准差进行归一化
    img_tensor = transforms.Normalize((0.1307,), (0.3081,))(img_tensor)

    return image, img_tensor  # 返回原始图像和处理后的张量


def predict_digit(image_path):
    """预测自定义图像中的数字"""
    # 创建模型实例
    model = CNN()
    # 加载预训练模型权重
    model.load_state_dict(torch.load('mnist_cnn_model.pth'))
    # 设置模型为评估模式(关闭Dropout等训练特有的层)
    model.eval()

    # 预处理输入图像
    original_img, img_tensor = preprocess_image(image_path)

    # 预测过程,不计算梯度以提高效率
    with torch.no_grad():
        # 前向传播,得到模型输出
        output = model(img_tensor)
        # 应用softmax将输出转换为概率分布
        probabilities = torch.softmax(output, dim=1)
        # 获取最高概率及其对应的数字类别
        confidence, predicted = torch.max(probabilities, 1)

    # 创建可视化窗口
    plt.figure(figsize=(12, 4))

    # 子图1:显示原始输入图像
    plt.subplot(1, 3, 1)
    plt.imshow(original_img, cmap='gray')
    plt.title('原始图像')
    plt.axis('off')  # 关闭坐标轴显示

    # 子图2:显示模型实际输入(归一化后的图像)
    plt.subplot(1, 3, 2)
    plt.imshow(img_tensor[0][0], cmap='gray')
    plt.title('模型输入')
    plt.axis('off')

    # 子图3:显示预测结果和置信度条形图
    plt.subplot(1, 3, 3)
    plt.bar(range(10), probabilities[0].numpy())
    plt.xticks(range(10))  # 设置x轴刻度为0-9
    plt.title(f'预测结果: {predicted.item()} (置信度: {confidence.item() * 100:.2f}%)')
    plt.xlabel('数字')
    plt.ylabel('概率')

    # 自动调整子图布局
    plt.tight_layout()
    # 显示图像
    plt.show()

    # 返回预测结果和置信度
    return predicted.item(), confidence.item() * 100


if __name__ == '__main__':
    # 指定要测试的图像路径,请替换为实际路径
    image_path = r"C:\Users\10532\Desktop\Study\test\Untitled.png"

    # 检查文件是否存在
    if not os.path.exists(image_path):
        print(f"错误:文件 '{image_path}' 不存在")
    else:
        # 执行预测
        digit, confidence = predict_digit(image_path)
        print(f"预测结果: {digit},置信度: {confidence:.2f}%")

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

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

相关文章

idea Maven 打包SpringBoot可执行的jar包

背景&#xff1a;当我们需要坐联调测试的时候&#xff0c;需要对接前端同事&#xff0c;则需要打包成jar包直接运行启动服务 需要将项目中的pom文件增加如下代码配置&#xff1a; <build><plugins><plugin><groupId>org.springframework.boot</gr…

HarmonyOs开发之——— ArkWeb 实战指南

HarmonyOs开发之——— ArkWeb 实战指南 谢谢关注!! 前言:上一篇文章主要介绍HarmonyOs开发之———合理使用动画与转场:CSDN 博客链接 一、ArkWeb 组件基础与生命周期管理 1.1 Web 组件核心能力概述 ArkWeb 的Web组件支持加载本地或在线网页,提供完整的生命周期回调体…

国标GB/T 12536-90滑行试验全解析:纯电动轻卡行驶阻力模型参数精准标定

摘要 本文以国标GB/T 12536-90为核心框架&#xff0c;深度解析纯电动轻卡滑行试验的完整流程与数据建模方法&#xff0c;提供&#xff1a; 法规级试验规范&#xff1a;从环境要求到数据采集全流程详解行驶阻力模型精准标定&#xff1a;最小二乘法求解 ( FAv^2BvC ) 的MATLAB实…

初识——QT

QT安装方法 一、项目创建流程 创建项目 入口&#xff1a;通过Qt Creator的欢迎页面或菜单栏&#xff08;文件→新建项目&#xff09;创建新项目。 项目类型&#xff1a;选择「Qt Widgets Application」。 路径要求&#xff1a;项目路径需为纯英文且不含特殊字符。 构建系统…

kkFileView文件文档在线预览镜像分享

kkFileView为文件文档在线预览解决方案&#xff0c;该项目使用流行的spring boot搭建&#xff0c;易上手和部署&#xff0c;基本支持主流办公文档的在线预览&#xff0c;如doc,docx,xls,xlsx,ppt,pptx,pdf,txt,zip,rar,图片,视频,音频等等 开源项目地址 https://gitee.com/kek…

实例分割AI数据标注 ISAT自动标注工具使用方法

文章目录 🌕ISAT安装和启动方法🌕下载和使用AI分割模型🌙SAM模型性能排行🌙手动下载sam模型 & sam模型下载路径🌕使用方法🌙从file中导入图片🌙点击左上角的图标进入分割模式🌙鼠标左键点击画面中的人则自动标注🌙点击右键该区域不标注🌙一个人一个人的…

Qt图表绘制(QtCharts)- 性能优化(13)

文章目录 1 批量替换代替追加1.1 测试11.2 测试21.3 测试3 2 开启OpenGL2.1 测试12.2 测试22.3 测试32.4 测试4 更多精彩内容&#x1f449;内容导航 &#x1f448;&#x1f449;Qt开发 &#x1f448;&#x1f449;QtCharts绘图 &#x1f448;&#x1f449;python开发 &#x1f…

如何在 Windows 10 或 11 上使用命令提示符安装 PHP

我们可以在 Windows 上从其官方网站下载并安装 PHP 的可执行文件,但使用命令提示符或 PowerShell 更方便。 PHP 并不是一种新的或不为人知的脚本语言,它已经存在并被全球数千名网络开发人员使用。它以开源许可并分发,广泛用于 LAMP 堆栈中。然而,与 Linux 相比,它在 Wind…

RK3588 ADB使用

安卓adb操作介绍 adb&#xff08;Android Debug Bridge&#xff09;是一个用于与安卓设备进行通信和控制的工具。adb可以通过USB或无线网络连接安卓设备&#xff0c;执行各种命令&#xff0c;如安装和卸载应用&#xff0c;传输文件&#xff0c;查看日志&#xff0c;运行shell命…

Please install it with pip install onnxruntime

无论怎么安装都是 Please install it with pip install onnxruntime 我python 版本是3.11 &#xff0c;我换成3.10 解决了

低损耗高效能100G O Band DWDM 10km光模块 | 支持密集波分复用

目录 前言 一、产品概述 100G QSFP28 O Band DWDM 10km光模块核心特点包括&#xff1a; 二、为何选择O Band DWDM方案&#xff1f; 1.低色散损耗&#xff0c;传输更稳定 2.兼容性强 三、典型应用场景 1.数据中心互联&#xff08;DCI&#xff09; 2.企业园区/智慧城市组网 3.电信…

第二十六天打卡

全局变量 global_var 全局变量是定义在函数、类或者代码块外部的变量&#xff0c;它在整个程序文件内都能被访问。在代码里&#xff0c; global_var 就是一个全局变量&#xff0c;下面是相关代码片段&#xff1a; print("\n--- 变量作用域示例 ---") global_var …

阿里云ECS部署Dify

一&#xff1a;在ECS上面安装Docker 关防火墙 sudo systemctl stop firewalld 检查防火墙状态 systemctl status firewalld sudo yum install -y yum-utils device-mapper-persistent-data lvm2 设置阿里镜像源&#xff0c;安装并启动docker [base] nameCentOS-$releas…

日志与策略模式

什么是设计模式 IT⾏业 ,为了让 菜鸡们不太拖⼤佬的后腿, 于是⼤佬们针对⼀些经典的常⻅的场景, 给定了⼀些对应的解决⽅案, 这个就是 设计模式 日志认识 计算机中的⽇志是记录系统和软件运⾏中发⽣事件的⽂件&#xff0c;主要作⽤是监控运⾏状态、记录异常信 息&#xff…

Jenkins 最佳实践

1. 在Jenkins中避免调度过载 过载Jenkins以同时运行多个作业可能导致资源竞争、构建速度变慢和系统性能问题。分配作业启动时间可以防止瓶颈&#xff0c;并确保更顺畅的执行。如何实现&#xff1f; 在Cron表达式中使用H&#xff1a;引入抖动&#xff08;jitter&#xff09;&a…

天能股份SAP系统整合实战:如何用8个月实现零业务中断的集团化管理升级

目录 天能股份SAP系统整合案例&#xff1a;技术驱动集团化管理的破局之路 一、企业背景&#xff1a;新能源巨头的数字化挑战 二、项目难点&#xff1a;制造业的特殊攻坚战 1. 生产连续性刚性需求 2. 数据整合三重障碍 3. 资源限制下的技术突围 三、解决方案&#xff1a;S…

uniapp-商城-59-后台 新增商品(属性的选中,进行过滤展示,filter,some,every和map)

前面讲了属性的添加&#xff0c;添加完成后&#xff0c;数据库中已经存在数据了&#xff0c;这时再继续商品的添加时&#xff0c;就可以进行属性的选择了。 在商品添加过程中&#xff0c;属性选择是一个关键步骤。首先&#xff0c;界面需要展示嵌套的属性数据&#xff0c;用户通…

B2C 商城转型指南:传统企业如何用 ZKmall模板商城实现电商化

在数字化浪潮席卷全球的当下&#xff0c;传统企业向电商转型已不再是选择题&#xff0c;而是关乎生存与发展的必答题。然而&#xff0c;缺乏技术积累、开发成本高、运营经验不足等问题&#xff0c;成为传统企业转型路上的 “拦路虎”。ZKmall模板商城以其低门槛、高灵活、强适配…

生成树协议 - STP

目录 BPDU STP选举机制 STP端口状态 STP计时器 STP拓扑变更机制 生成树协议&#xff08;Spanning Tree Protocol&#xff09;&#xff0c;简写为STP。 STP是二层网络中用于消除环路的协议&#xff0c;通过阻塞冗余链路&#xff0c;使可用链路在拓扑上呈现出无环的树结构&…

计算机指令分类和具体的表示的方式

1.关于计算机的指令系统 下面的这个就是我们的一个简单的计算机里面涉及到的指令&#xff1a; m就是我们的存储器里面的地址&#xff0c;可以理解为memory这个意思&#xff0c;r可以理解为rom这样的单词的首字母&#xff0c;帮助我们去进行这个相关的指令的记忆&#xff0c;不…