当前位置: 首页 > news >正文

传统神经网络实现-----手写数字识别(MNIST)项目

完整代码:

# import torch
# print(torch.__version__)#1.X     1、验证安装的开发环境是否正确,'''
MNIST包含70,000张手写数字图像: 60,000张用于训练,10,000张用于测试。
图像是灰度的,28x28像素的,并且居中的,以减少预处理和加快运行。
'''
import torch
from torch import nn    #导入神经网络模块,
from torch.utils.data import DataLoader #数据包管理工具,打包数据,
from torchvision import datasets #封装了很多与图像相关的模型,及数据集
from torchvision.transforms import ToTensor #数据转换,张量,将其他类型的数据转换为tensor张量,numpy array,dataframe'''下载训练数据集(包含训练图片+标签)'''
training_data = datasets.MNIST( #跳转到函数的内部源代码,pycharm 按下ctrl +鼠标点击root="data",#表示下载的手写数字 到哪个路径。60000train=True,#读取下载后的数据 中的 训练集download=True,#如果你之前已经下载过了,就不用再下载transform=ToTensor(),   #张量,图片是不能直接传入神经网络模型
)   #对于pytorch库能够识别的数据一般是tensor张量.
print(len(training_data))
# datasets.MNIST的参数:
#   root(string): 表示数据集的根目录,
#   train(bool, optional): 如果为True,则从training.pt创建数据集,否则从test.pt创建数据集
#   download(bool, optional): 如果为True,则从internet下载数据集并将其放入根目录。如果数据集已下载,则不会再次下载
#   transform(callable, optional): 接收PIL图片并返回转换后版本图片的转换函数'''下载测试数据集(包含训练图片+标签) '''
test_data = datasets.MNIST(root="data",train=False,download=True,transform=ToTensor(),#Tensor是在深度学习中提出并广泛应用的数据类型,它与深度学习框架(如 PyTorch、TensorFlow)紧密集成,方便进行神经网络的训练和推理。
)#NumPy 数组只能在CPU上运行。Tensor可以在GPU上运行,这在深度学习应用中可以显著提高计算速度。
print(len(test_data))# '''展示手写字图片,把训练数据集中的前59000张图片展示一下'''
# from matplotlib import pyplot as plt
# figure = plt.figure()
# for i in range(9):#
#     img, label = training_data[i+59000]#提取第59000张图片
#
#     figure.add_subplot(3, 3, i+1)#图像窗口中创建多个小窗口,小窗口用于显示图片
#     plt.title(label)
#     plt.axis("off")  # plt.show(I)#显示矢量,
#     plt.imshow(img.squeeze(), cmap="gray")  #plt.imshow()将NumPy数组data中的数据显示为图像,并在图形窗口中显示该图像
#     a = img.squeeze() # img.squeeze()从张量img中去掉维度为1的。如果该维度的大小不为1则张量不会改变。#cmap="gray"表示使用灰度色彩映射来显示图像。这意味着图像将以灰度模式显示
# plt.show()'''创建数据DataLoader(数据加载器)batch_size:将数据集分成多份,每一份为batch_size个数据。优点:可以减少内存的使用,提高训练速度。
'''
train_dataloader = DataLoader(training_data, batch_size=64)#64张图片为一个包,1、损失函数2、GPU一次性接受的图片个数
test_dataloader = DataLoader(test_data, batch_size=64)
for X, y in test_dataloader:#X是表示打包好的每一个数据包print(f"Shape of X [N, C, H, W]: {X.shape}")#print(f"Shape of y: {y.shape} {y.dtype}")break'''判断当前设备是否支持GPU,其中mps是苹果m系列芯片的GPU。'''#返回cuda,mps。CPU   m1 ,m2  集显CPU+GPU  RTX3060,
device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"
print(f"Using {device} device")#字符串的格式化。  CUDA驱动软件的功能:pytorch能够去执行cuda的命令,cuda通过GPU指令集去控制GPU
#神经网络的模型也需要传入到GPU,1个batchsize的数据集也需要传入到GPU,才可以进行训练。''' 定义神经网络  类的继承这种方式'''
class NeuralNetwork(nn.Module):#通过调用类的形式来使用神经网络,神经网络的模型,nn.moduledef __init__(self):#python基础关于类,self类自己本身super().__init__()#继承的父类初始化self.flatten = nn.Flatten()#展开,创建一个展开对象flattenself.hidden1 = nn.Linear(28*28, 128)#第1个参数:有多少个神经元传入进来,第2个参数:有多少个数据传出去前一层神经元的个数,当前本层神经元个数self.hidden2 = nn.Linear(128, 256)#为什么你要用128self.out = nn.Linear(256, 10)#输出必需和标签的类别相同,输入必须是上一层的神经元个数def forward(self, x):   #前向传播,你得告诉它  数据的流向。是神经网络层连接起来,函数名称不能改。当你调用forward函数的时候,传入进来的图像数据x = self.flatten.forward(x)     #图像进行展开  self.flatten.forwardx = self.hidden1.forward(x)x = torch.relu(x) #激活函数,torch使用的relu函数 relu,tanhx = self.hidden2.forward(x)x = torch.relu(x)x = self.out.forward(x)return xmodel = NeuralNetwork().to(device)#把刚刚创建的模型传入到Gpu
print(model)def train(dataloader, model, loss_fn, optimizer):model.train()#告诉模型,我要开始训练,模型中w进行随机化操作,已经更新w。在训练过程中,w会被修改的
#pytorch提供2种方式来切换训练和测试的模式,分别是:model.train() 和 model.eval()。
# 一般用法是:在训练开始之前写上model.trian(),在测试时写上 model.eval() 。batch_size_num = 1  #统计 训练的batch数量for X, y in dataloader:                 #其中batch为每一个数据的编号X, y = X.to(device), y.to(device)   #把训练数据集和标签传入cpu或GPUpred = model(X)             #.forward可以被省略,父类中已经对此功能进行了设置。自动初始化 w权值loss = loss_fn(pred, y)             #通过交叉熵损失函数计算损失值loss# Backpropagation 进来一个batch的数据,计算一次梯度,更新一次网络optimizer.zero_grad()               #梯度值清零loss.backward()                     #反向传播计算得到每个参数的梯度值woptimizer.step()                    #根据梯度更新网络w参数loss_value = loss.item()                  #从tensor数据中提取数据出来,tensor获取损失值if batch_size_num %100  ==0:print(f"loss: {loss_value:>7f}  [number:{batch_size_num}]")batch_size_num += 1def test(dataloader, model, loss_fn):size = len(dataloader.dataset)#10000num_batches = len(dataloader)#打包的数量model.eval()    #测试,w就不能再更新。test_loss, correct = 0, 0   #with torch.no_grad():   #一个上下文管理器,关闭梯度计算。当你确认不会调用Tensor.backward()的时候。这可以减少计算所用内存消耗。for X, y in dataloader:X, y = X.to(device), y.to(device)  #送到GPUpred = model.forward(X)test_loss += loss_fn(pred, y).item() #test_loss是会自动累加每一个批次的损失值correct += (pred.argmax(1) == y).type(torch.float).sum().item()a = (pred.argmax(1) == y)  #dim=1表示每一行中的最大值对应的索引号,dim=0表示每一列中的最大值对应的索引号b = (pred.argmax(1) == y).type(torch.float)test_loss /= num_batches  #能来衡量模型测试的好坏。correct /= size  #平均的正确率print(f"Test result: \n Accuracy: {(100*correct)}%, Avg loss: {test_loss}")loss_fn = nn.CrossEntropyLoss() #创建交叉熵损失函数对象,因为手写字识别中一共有10个数字,输出会有10个结果
# L1Loss:L1损失,也称为平均绝对误差(Mean Absolute Error, MAE)。它计算预测值与真实值之间的绝对差值的平均值。
# NLLLoss:负对数似然损失(Negative Log Likelihood Loss)。它用于多分类问题,通常与LogSoftmax输出层配合使用。
# NLLLoss2d:这是NLLLoss的一个特殊版本,用于处理2D图像数据。在最新版本的PyTorch中,这个损失函数可能已经被整合到NLLLoss中,通过指定reduction参数来实现同样的功能。
# PoissonNLLLoss:泊松负对数似然损失,用于泊松回归问题。
# GaussianNLLLoss:高斯负对数似然损失,用于高斯分布(正态分布)的回归问题。
# KLDivLoss:Kullback-Leibler散度损失,用于度量两个概率分布之间的差异。
# MSELoss:均方误差损失(Mean Squared Error Loss),计算预测值与真实值之间差值的平方的平均值。
# BCELoss:二元交叉熵损失(Binary Cross Entropy Loss),用于二分类问题。
# BCEWithLogitsLoss:结合了Sigmoid激活函数和二元交叉熵损失的损失函数,用于提高数值稳定性。
# HingeEmbeddingLoss:铰链嵌入损失,用于学习非线性嵌入或半监督学习。
# MultiLabelMarginLoss:多标签边际损失,用于多标签分类问题。
# SmoothL1Loss:平滑L1损失,是L1损失和L2损失(MSE)的结合,旨在避免梯度爆炸问题。
# HuberLoss:Huber损失,与SmoothL1Loss类似,但有一个可调的参数来控制L1和L2损失之间的平衡。
# SoftMarginLoss:软边际损失,用于二分类问题,可以看作是Hinge损失的一种软化版本。
# CrossEntropyLoss:交叉熵损失,用于多分类问题。它结合了LogSoftmax和NLLLoss的功能。
# MultiLabelSoftMarginLoss:多标签软边际损失,用于多标签二分类问题。
# CosineEmbeddingLoss:余弦嵌入损失,用于学习非线性嵌入,通过余弦相似度来度量样本之间的相似性。
# MarginRankingLoss:边际排序损失,用于排序问题,如学习到排序的嵌入空间。
# MultiMarginLoss:多边际损失,用于多分类问题,旨在优化分类边界的边际。
# TripletMarginLoss:三元组边际损失,用于学习嵌入空间中的距离度量,通常用于人脸识别或图像检索等任务。
# TripletMarginWithDistanceLoss:这是TripletMarginLoss的一个变体,允许使用自定义的距离函数。
# CTCLoss:连接时序分类损失(Connectionist Temporal Classification Loss),用于序列到序列的学习问题,特别是当输出序列的长度不固定时(如语音识别)。#一会改成adam优化器   梯度下降
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)#创建一个优化器,SGD为随机梯度下降算法
# #params:要训练的参数,一般我们传入的都是model.parameters()。
# #lr:learning_rate学习率,也就是步长。#loss表示模型训练后的输出结果与 样本标签的差距。如果差距越小,就表示模型训练越好,越逼近于真实的模型。# train(train_dataloader, model, loss_fn, optimizer)#训练1次完整的数据,多轮训练,
# test(test_dataloader, model, loss_fn)epochs = 10 #到底选择多少呢?
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)#10次训练
print("Done!")
test(test_dataloader, model, loss_fn)# # #分析sigmiod,relu
# # # sgd,Adam

按代码模块进行解析:

第一部分:环境验证与数据加载
# import torch
# print(torch.__version__)#1.X     1、验证安装的开发环境是否正确,
  • 注释掉了,用于检查 PyTorch 是否安装成功。


import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets
from torchvision.transforms import ToTensor

  • 导入 PyTorch 核心库及相关模块:

    • nn:构建神经网络。

    • DataLoader:批量加载数据。

    • datasets:内置数据集(如 MNIST)。

    • ToTensor:将图片转为 Tensor 格式。


training_data = datasets.MNIST(root="data",train=True,download=True,transform=ToTensor(),
)

  • 下载 训练集(60,000 张图):

    • root="data":保存到本地 data/ 文件夹。

    • transform=ToTensor():将图片转为 Tensor(灰度值归一化到 [0, 1])。


test_data = datasets.MNIST(root="data",train=False,download=True,transform=ToTensor(),
)

  • 下载 测试集(10,000 张图)。


train_dataloader = DataLoader(training_data, batch_size=64)
test_dataloader = DataLoader(test_data, batch_size=64)

  • 使用 DataLoader 将数据打包成 批次(每批 64 张图),方便训练。


 第二部分:设备选择与模型定义

device = "cuda" if torch.cuda.is_available() else "mps" if torch.backends.mps.is_available() else "cpu"

  • 自动选择设备:

    • 优先使用 NVIDIA GPU(cuda);

    • 其次 Apple 芯片(mps);

    • 最后回退到 CPU。


class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()self.hidden1 = nn.Linear(28*28, 128)self.hidden2 = nn.Linear(128, 256)self.out = nn.Linear(256, 10)def forward(self, x):x = self.flatten(x)x = torch.relu(self.hidden1(x))x = torch.relu(self.hidden2(x))x = self.out(x)return x

  • 定义一个 三层全连接神经网络

    • 输入层:28×28 = 784 像素;

    • 隐藏层1:128 个神经元;

    • 隐藏层2:256 个神经元;

    • 输出层:10 个类别(0~9 数字);

    • 激活函数:ReLU。


model = NeuralNetwork().to(device)

  • 将模型迁移到 GPU(或 CPU)。


第三部分:训练与测试函数

def train(dataloader, model, loss_fn, optimizer):model.train()for batch, (X, y) in enumerate(dataloader):X, y = X.to(device), y.to(device)pred = model(X)loss = loss_fn(pred, y)optimizer.zero_grad()loss.backward()optimizer.step()if batch % 100 == 0:print(f"loss: {loss.item():.7f} [batch {batch}]")

  • 训练函数

    • 每个批次前向传播 → 计算损失 → 反向传播 → 更新权重;

    • 每 100 个批次打印一次损失值。


def test(dataloader, model, loss_fn):model.eval()test_loss, correct = 0, 0with torch.no_grad():for X, y in dataloader:X, y = X.to(device), y.to(device)pred = model(X)test_loss += loss_fn(pred, y).item()correct += (pred.argmax(1) == y).type(torch.float).sum().item()test_loss /= len(dataloader)correct /= len(dataloader.dataset)print(f"Test Accuracy: {100*correct:.2f}%, Avg loss: {test_loss:.4f}")

  • 测试函数

    • 不更新权重(model.eval());

    • 计算整体损失与准确率。


第四部分:损失函数与优化器

loss_fn = nn.CrossEntropyLoss()
optimizer = torch.optim.Adam(model.parameters(), lr=0.005)

  • 使用 交叉熵损失(适合多分类);

  • 使用 Adam 优化器(比 SGD 更稳定)。


第五部分:训练循环

epochs = 10
for t in range(epochs):print(f"Epoch {t+1}\n-------------------------------")train(train_dataloader, model, loss_fn, optimizer)
print("Done!")
test(test_dataloader, model, loss_fn)

  • 训练 10 轮

  • 每轮遍历一次完整训练集;

  • 最后测试模型性能。

代码模块具体逐行逐句解释:

class NeuralNetwork(nn.Module):def __init__(self):super().__init__()self.flatten = nn.Flatten()self.hidden1 = nn.Linear(28*28, 128)self.hidden2 = nn.Linear(128, 256)self.out = nn.Linear(256, 10)def forward(self, x):x = self.flatten(x)x = torch.relu(self.hidden1(x))x = torch.relu(self.hidden2(x))x = self.out(x)return x
第一部分:类定义与初始化 (__init__ 方法)

class NeuralNetwork(nn.Module):

作用:声明一个继承自 PyTorch 基类 nn.Module 的新类
含义:所有自定义神经网络必须继承此类才能享受 PyTorch 的训练/推理功能(如 model.train(), model.eval()

super().__init__()

作用:调用父类 nn.Module 的构造函数
重要性:初始化模块的必要内部结构(如参数注册器),不可省略

self.flatten = nn.Flatten()

作用:创建一个展平层对象
功能详解:将多维输入(如图像 [B, H, W])压缩为一维向量 [B, H×W]
典型场景:连接卷积层和非全连接层时的过渡操作

self.hidden1 = nn.Linear(28*28, 128)

作用:定义第一个全连接层(又称密集层)
参数解析

  • in_features=28*28=784:输入特征数(对应 28×28 图像的像素总数)

  • out_features=128:本层神经元数量
    内部机制:自动创建权重矩阵 W₁ (形状 784×128) 和偏置向量 b₁ (长度 128)

self.hidden2 = nn.Linear(128, 256)

作用:定义第二个全连接层
参数解析

  • in_features=128:前一层的输出特征数

  • out_features=256:本层神经元数量
    内部机制:自动创建权重矩阵 W₂ (形状 128×256) 和偏置向量 b₂ (长度 256)

self.out = nn.Linear(256, 10)

作用:定义输出层
特殊设计

  • out_features=10:对应分类任务的类别数(如 MNIST 手写数字识别)

  • 输出未经过激活函数(直接输出 logits),配合交叉熵损失函数使用


第二部分:前向传播 (forward 方法)

def forward(self, x):

作用:定义数据的前向传播路径
关键性质:每次调用 model(input) 时会自动执行此方法

x = self.flatten(x)

作用:展平输入张量
示例

  • 输入形状 [batch_size, 28, 28] → 输出形状 [batch_size, 784]
    必要性:全连接层只能接受一维特征向量

x = torch.relu(self.hidden1(x))

作用:通过第一隐藏层并进行 ReLU 激活
计算过程

  1. 线性变换:x = W₁·x + b₁

  2. ReLU 激活:x[x<0]=0(保留正值,引入非线性)
    设计理由:解决线性模型无法拟合复杂模式的问题

x = torch.relu(self.hidden2(x))

作用:通过第二隐藏层并进行 ReLU 激活
计算过程

  1. 线性变换:x = W₂·x + b₂

  2. ReLU 激活:同上
    效果:进一步提取高阶特征,增加模型表达能力

x = self.out(x)

作用:通过输出层生成最终结果
注意:此处不添加激活函数
原因:分类任务通常在损失函数中结合 LogSoftmax(如 CrossEntropyLoss),logits 更灵活可控

return x

作用:返回模型输出
输出形式:原始 logits(未归一化的概率分数)
后续处理:通常会接入软最大值函数(Softmax)进行概率转换,或直接用于计算损失

def train(dataloader, model, loss_fn, optimizer):model.train()for batch, (X, y) in enumerate(dataloader):X, y = X.to(device), y.to(device)pred = model(X)loss = loss_fn(pred, y)optimizer.zero_grad()loss.backward()optimizer.step()if batch % 100 == 0:print(f"loss: {loss.item():.7f} [batch {batch}]")

第1行:model.train()

功能:将模型设置为 训练模式
底层逻辑

  • 激活模型中所有适用于训练的特殊组件。

    • 示例nn.Dropout(p=0.5) 在训练时会随机屏蔽50%的神经元,而在推理模式(model.eval())下无效。

  • 确保模型处于可学习状态(参数注册钩子启用)。
    关键性:若省略此步,模型可能因未启用必要层(如 Dropout)导致性能下降或错误。


第2行:for batch, (X, y) in enumerate(dataloader):

功能:遍历数据集的一个完整周期(Epoch)
参数解析

  • dataloader:PyTorch 的 DataLoader 对象,负责按批次加载数据。

  • enumerate():同时获取当前批次的索引 batch 和数据 (X, y)
    典型输出

    • X: 输入特征张量,形状为 [batch_size × input_dim](如图像数据为 [B, C, H, W])。

    • y: 目标标签张量,形状为 [batch_size × output_dim](分类任务通常为 one-hot 编码或类别索引)。
      设计目的:通过迭代实现 mini-batch SGD(随机梯度下降),逐步优化模型参数。


第3-4行:X, y = X.to(device), y.to(device)

功能:将数据迁移到指定计算设备(CPU/GPU)
底层逻辑

  • device 通常是预定义的变量(如 torch.device('cuda')),表示可用的硬件资源。

  • .to(device) 方法执行以下操作:

    • 数据搬运:将张量从 CPU 内存复制到 GPU 显存(若 device='cuda')。

    • 类型匹配:自动转换数据类型以匹配模型参数的类型(如 float32)。
      重要性:确保模型与数据在同一设备上运算,否则会抛出 RuntimeError: ... not on the same device
      注意:此操作仅影响张量的存储位置,不改变其数值内容。


第5行:pred = model(X)

功能:执行前向传播(Forward Propagation)
计算流程

  1. 输入 X 经模型各层依次变换(如线性层、激活函数、归一化层等)。

  2. 输出 pred 是模型对输入 X 的原始预测值(Logits),尚未应用任何激活函数。
    维度示例

  • 输入形状:[batch_size, input_dim] → 输出形状:[batch_size, num_classes](分类任务)。
    注意:此处保持线性输出,供损失函数后续处理。


第6行:loss = loss_fn(pred, y)

功能:计算当前批次的损失值
核心机制

  • loss_fn 是预定义的损失函数(如 nn.CrossEntropyLoss()nn.MSELoss())。

  • 对比模型输出 pred 与真实标签 y,量化预测误差。
    数学本质

    • 分类任务:交叉熵损失 L = -Σ(y * log(softmax(pred)))

    • 回归任务:均方误差 L = ||pred - y||²_2
      作用:为反向传播提供优化目标,指导参数更新方向。


第7行:optimizer.zero_grad()

功能:清空优化器的梯度缓存
底层逻辑

  • PyTorch 采用 累积梯度 策略,每次调用 loss.backward() 会将新梯度累加到现有梯度上。

  • 此操作将所有可训练参数的梯度置零,防止跨批次梯度混合。
    必要性:若不执行此步,梯度会指数级增长,导致参数更新异常剧烈(如爆炸性梯度)。
    内部实现:遍历模型的所有可训练参数,执行 param.grad = None


第8行:loss.backward()

功能:执行反向传播(Backward Propagation)
计算流程

  1. 根据链式法则自动计算损失对每个参数的梯度。

  2. 梯度存储在 param.grad 属性中(仅存在于 requires_grad=True 的参数)。
    技术核心:利用自动微分系统高效计算复杂计算图的梯度。
    注意:此操作 不会立即更新参数,仅计算梯度。


第9行:optimizer.step()

功能:根据梯度更新模型参数
执行过程

  1. 优化器(如 SGD、Adam)按照预设规则(学习率、动量等)更新参数。

    • SGD 示例param = param - lr * param.grad

  2. 完成一次参数更新后,梯度会被自动清零(部分优化器除外)。
    效果:使模型向损失降低的方向调整参数。
    注意:此操作是参数更新的唯一入口,必须在 zero_grad() 之后调用。


第10-11行:if batch % 100 == 0: print(f"loss: {loss.item():.7f} [batch {batch}]")

功能:定期打印训练进度
实现细节

  • batch % 100 == 0:每处理 100 个批次打印一次日志。

  • loss.item():将张量转换为 Python 标量(浮点数),用于格式化输出。
    输出示例loss: 0.1234567 [batch 100]
    用途:监控训练稳定性,辅助调试(如发现 NaN 或爆炸性损失)。


文章转载自:

http://fMrvPaON.zczmc.cn
http://NUCbumSj.zczmc.cn
http://A0bA8W12.zczmc.cn
http://MKEraKw3.zczmc.cn
http://gx5QyhY1.zczmc.cn
http://gu3y6tz0.zczmc.cn
http://oR0sdeco.zczmc.cn
http://EpcoOZKx.zczmc.cn
http://pcM7DUWC.zczmc.cn
http://2FvKazMP.zczmc.cn
http://Lmkyts6u.zczmc.cn
http://gEXXw0K0.zczmc.cn
http://Cyi28uZK.zczmc.cn
http://vW1NyzcV.zczmc.cn
http://pQ7h2Zav.zczmc.cn
http://EKOMGhRN.zczmc.cn
http://zhUMPUxW.zczmc.cn
http://Xerrs8NH.zczmc.cn
http://3C5b0Kyt.zczmc.cn
http://0Jzr5ld0.zczmc.cn
http://ggrhw4aM.zczmc.cn
http://GgzzX2FS.zczmc.cn
http://fgec8F35.zczmc.cn
http://F3YnShWo.zczmc.cn
http://XGULspUB.zczmc.cn
http://5ChE5767.zczmc.cn
http://YolJS6XZ.zczmc.cn
http://WCwtPKbZ.zczmc.cn
http://uMVLg2m9.zczmc.cn
http://CrNEYZoN.zczmc.cn
http://www.dtcms.com/a/368692.html

相关文章:

  • Maven常见问题解决方案
  • 一文详解深度学习中神经网络的各层结构与功能!
  • Java全栈开发工程师面试实录:从基础到实战的深度探讨
  • Unity打包Android应用常见问题解决指南
  • Snow Shot(截图工具) v0.2.6
  • LeNet-5:手写数字识别经典CNN
  • C++ opencv RTSP小工具 RTSP流播放、每一帧保存
  • android View详解—动画
  • 2024年9月GESPC++三级真题解析(含视频)
  • ASP.NET Core文件分片上传
  • OCA、OCP、OCM傻傻分不清?Oracle认证就看这篇
  • 面试了一个外包公司,面试不到5分钟就出来,这问题问得有点变态。。。。。。
  • Matlab使用小技巧合集(系列四):Table类型高效用法与数据处理实战
  • 25高教社杯数模国赛【C题超高质量思路+可运行代码】第十弹
  • WinForms 项目里生成时选择“首选目标平台 32 位导致有些电脑在获取office word对象时获取不到
  • ANSYS 热力耦合计算
  • UE4 Mac构建编译报错 no member named “disjunction” in namespace “std”
  • 深度相机详解
  • vue 经常写的echarts图表模块结构抽取
  • 蚂蚁 S21e XP Hyd 3U 860T矿机性能分析与技术特点
  • Python迭代协议完全指南:从基础到高并发系统实现
  • CT影像寻找皮肤轮廓预处理
  • 7种流行Prompt设计模式详解:适用场景与最佳实践
  • uni-app 项目 iOS 上架踩坑经验总结 从证书到审核的避坑指南
  • 3.3_第一行之hard_local_irq_disable
  • 汽车 信息娱乐系统 概览
  • 将已有 Vue 项目通过 Electron 打包为桌面客户端的完整步骤
  • Nginx 配置片段主要用于实现​​正向代理​​,可以用来转发 HTTP 和 HTTPS 请求
  • 有鹿机器人的365天奇幻日记:我在景区当扫地僧
  • C++算法专题学习——分治