基于BP與CNN的圖像分類模型構建、超參數優化及性能對比研究?

一、實驗目的

實驗目標

構建基于神經網絡模型的數據分析與模式識別框架,探明神經網絡在大數據分析中的意義。

實驗任務

構建基于深度 BP 神經網絡與卷積神經網絡的數據分析與模式識別框架,將數據集 MNISTCIFAR-10 分別在兩種模型中訓練,并比較測試效果。

使用數據集

  • MNIST 數據集

  • CIFAR-10 數據集

二、實驗原理

階段一分析:

分析問題需求,明確分類任務目標

在本階段,我們的目標是構建一個圖像分類系統,能夠將輸入圖像準確分類到對應的類別。首先,搭建數據讀取與預處理模塊,需要調用MNIST和CIFAR-10兩個標準圖像數據集作為實驗數據。然后,搭建數據與模型接口,為以后將這兩個數據集放入模型中做好準備。接下來,實現模型評估模塊,按照老師所講的,計算分類評估指標錯誤率與精確度,最后在可視化中搭建roc曲線。

階段二分析(BP神經網絡):

BP (Back Propagation)神經網絡也是前饋神經網絡,只是它的參數權重值是由反向傳播學習算法進行調整的

BP 神經網絡模型拓撲結構包括輸入層、隱層和輸出層,利用激活函數來實現從輸入到輸出的任意非線性映射,從而模擬各層神經元之間的交互

基本步驟:初始化網絡權值和神經元的閾值,一般通過隨機的方式進行初始化前向傳播: 計算隱層神經元和輸出層神經元的輸出后向傳播: 根據目標函數公式修正權值。

BP 神經網絡的核心思想是由后層誤差推導前層誤差,一層一層的反傳,最終獲得各層的誤差估計,從而得到參數的權重值。由于權值參數的運算量過大,一般采用梯度下降法來實現

輸入層是神經網絡的起點,其作用是將外部數據輸入模型。在圖像分類任務中,圖像需要先被展平為一維向量(如 MNIST 的 28x28 圖像被展平為 784 維向量),并作為輸入層的節點傳入網絡。輸入層本身不做任何計算,只負責數據的傳遞。

神經網絡隱藏層

隱藏層是網絡中最核心的部分,用于提取特征與學習數據之間的非線性關系。每個隱藏層由多個神經元(節點)構成,節點之間通過權重連接。每個神經元會對其輸入做一次線性加權求和,再通過激活函數進行非線性變換(如 ReLU、Sigmoid、Tanh 等),提高模型的擬合與表達能力。多個隱藏層串聯構成了“深度”網絡。

神經網絡輸出層

輸出層的作用是將模型內部的高維特征最終映射為分類結果。對于多分類任務(如本實驗中的 MNIST 和 CIFAR-10,均為 10 類),輸出層一般設置為一個Linear全連接層,輸出維度為類別數(10),并通過Softmax 函數 轉換為概率形式,用于分類決策。

階段三分析(CNN神經網絡)

卷積神經網絡是人工神經網絡的一種,由對貓的視覺皮層的研究發展而來,視覺皮層細胞對視覺子空間更敏感,通過子空間的平鋪掃描實現對整個視覺空間的感知。

卷積神經網絡目前是深度學習領域的熱點,尤其是圖像識別和模式分類方面,優勢在于具有共享權值的網絡結構和局部感知(也稱為稀疏連接)的特點,能夠降低神經網絡的運算復雜度。

卷積層和子采樣層是特征提取功能的核心模塊,卷積神經網絡的低層由卷積層和子采樣層交替組成,在保持特征不變的情況下減少維度空間和計算時間,更高層次是全連接層,輸入是由卷積層和子采樣層提取到的特征,最后一層是輸出層,可以是一個分類器,采用邏輯回歸、Softmax回歸、支持向量機等進行模式分類,也可以直接輸出某一結果。

卷積層

通過卷積層的運算,可以將輸入信號在某一特征上加強,從而實現特征的提取,也可以排除干擾因素,從而降低特征的噪聲。卷積操作是指將一個可移動的小窗口(稱為數據窗口)與圖像進行逐元素相乘然后相加的操作。這個小窗口其實是一組固定的權重,它可以被看作是一個特定的濾波器(filter)或卷積核。

池化層

池化層是一種向下采樣的形式,在神經網絡中也稱之為子采樣層。一般使用最大池化將特征區域中的最大值作為新的抽象區域的值,減少數據的空間大小。參數數量和運算量也會減少,減少全連接的數量和復雜度,一定程度上可以避免過擬合。池化的結果是特征減少、參數減少。

全連接層

卷積層得到的每張特征圖表示輸入信號的一種特征,而它的層數越高表示這一特征越抽象,為了綜合低層的每個卷積層特征,用全連接層將這些特征結合到一起,然后用Softmax進行分類或邏輯回歸分析。

三、實驗代碼

3.1 構建數據分析與模式識別框架(第四周)

搭建數據讀取與預處理模塊(支持 MNIST / CIFAR-10)

數據讀取與預處理部分主要功能是根據用戶選擇加載 MNIST 或 CIFAR-10 數據集。

主要思路:使用torchvision.datasets 提供的接口自動下載并加載數據,同時通過 transforms 對圖像進行預處理,包括將圖像轉換為張量 (ToTensor) 并進行標準化(使像素值服從指定均值和標準差的分布),從而提升模型訓練的效果與穩定性。

最終返回處理后的訓練集,并輸出圖像數量和尺寸信息,便于后續模型訓練使用。

ps:使用 K-Fold 方法分解數據集(k=5)放在了另一模塊,分解后會直接訓練

def load_dataset(use_mnist=True):if use_mnist:transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)else:transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))])dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)print(f"加載數據集完成:{len(dataset)}張圖像,尺寸為 {dataset[0][0].shape}")return dataset
搭建數據與模型接口模塊

這一模塊作為數據與模型的接口,核心目的是根據用戶選擇動態構建不同類型的神經網絡模型。

函數 get_model 接收模型類型(bpcnn)和輸入數據的形狀等參數:當選擇 bp 時,將圖像展平成一維向量傳入多層感知機 DeepBPNet;當選擇 cnn 時,保留圖像的通道信息并構建卷積神經網絡 CustomCNN

同時通過 **kwargs 支持對網絡結構參數(如初始化方式、層數等)進行靈活配置。該接口實現了模型結構的統一調用,便于后續訓練與評估過程的模塊化管理。

# ========== 數據與模型接口 ==========
def get_model(model_type='bp', input_shape=(1, 28, 28), num_classes=10, **kwargs):if model_type == 'bp':input_size = np.prod(input_shape)return DeepBPNet(input_size=input_size, num_classes=num_classes, **kwargs)elif model_type == 'cnn':return CustomCNN(in_channels=input_shape[0], num_classes=num_classes, **kwargs)else:raise ValueError("模型必須是'bp'或者'cnn'")
搭建模型評估模塊

這一模塊是整個實驗的核心部分——模型評估模塊。

其主要功能是在訓練過程中使用 K-Fold 交叉驗證 方法(本實驗設定 k=5),將原始數據劃分為訓練集和驗證集。

在每一折中,首先利用用戶指定的模型類型(CNN 或 BP)通過 get_model 動態構建模型,并進行若干輪次的訓練。

接著,在驗證集中進行推理,計算預測結果與真實標簽的準確率(Accuracy)與對數損失(Log Loss)。每折的結果都會記錄并輸出,

最終返回所有折次的評估指標和分類概率,為模型表現對比與后續可視化分析提供基礎。

# ========== 模型評估模塊 ==========
def evaluate_model_kfold(dataset, model_type='cnn', k_folds=5, batch_size=64, num_classes=10, device=None, epochs=1, **kwargs):if device is None:device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
?indices = list(range(len(dataset)))kf = KFold(n_splits=k_folds, shuffle=True, random_state=42)
?all_fold_metrics = []all_probs = []all_targets = []
?for fold, (train_idx, val_idx) in enumerate(kf.split(indices)):print(f"\n 訓練輪數 {fold + 1}/{k_folds}")
?train_subset = Subset(dataset, train_idx)val_subset = Subset(dataset, val_idx)train_loader = DataLoader(train_subset, batch_size=batch_size, shuffle=True)val_loader = DataLoader(val_subset, batch_size=batch_size, shuffle=False)
?sample_input, _ = next(iter(train_loader))model = get_model(model_type=model_type,input_shape=sample_input.shape[1:],num_classes=num_classes,**kwargs).to(device)
?criterion = nn.CrossEntropyLoss()optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
?# === 訓練階段 ===model.train()for epoch in range(epochs):for inputs, labels in train_loader:inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()
?# === 驗證階段 ===model.eval()y_true, y_pred, y_prob = [], [], []
?with torch.no_grad():for inputs, labels in val_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)probs = F.softmax(outputs, dim=1)preds = torch.argmax(probs, dim=1)
?y_true.extend(labels.cpu().numpy())y_pred.extend(preds.cpu().numpy())y_prob.extend(probs.cpu().numpy())
?acc = accuracy_score(y_true, y_pred)loss = log_loss(y_true, y_prob, labels=list(range(num_classes)))
?all_fold_metrics.append({'fold': fold + 1, 'accuracy': acc, 'loss': loss})all_probs.extend(y_prob)all_targets.extend(y_true)
?print(f" Fold {fold + 1} Accuracy: {acc:.4f}, Loss: {loss:.4f}")
?return all_fold_metrics, np.array(all_probs), np.array(all_targets)
?
搭建模型評估可視化模塊

這一模塊是模型評估可視化部分,主要功能是繪制多分類任務中的 ROC 曲線,幫助我們直觀判斷模型對每一類別的區分能力。

首先通過 label_binarize 對目標標簽進行 One-Hot 編碼,然后計算每個類別的真正率(TPR)與假正率(FPR),并進一步求得每類的 AUC(曲線下面積)作為性能指標。

最終利用 Matplotlib 對每個類別的 ROC 曲線進行繪圖,并可選擇保存或直接展示。該模塊能有效展示模型對不同類別的分類效果,提供輔助判斷和模型優化依據。

def plot_multiclass_roc(probs, targets, num_classes, save_path=None):targets_onehot = label_binarize(targets, classes=list(range(num_classes)))
?fpr = dict()tpr = dict()roc_auc = dict()
?for i in range(num_classes):fpr[i], tpr[i], _ = roc_curve(targets_onehot[:, i], probs[:, i])roc_auc[i] = auc(fpr[i], tpr[i])
?plt.figure(figsize=(10, 8))for i in range(num_classes):plt.plot(fpr[i], tpr[i], label=f"Class {i} (AUC = {roc_auc[i]:.2f})")
?plt.plot([0, 1], [0, 1], 'k--', label='Random')plt.xlim([0.0, 1.0])plt.ylim([0.95, 1.05])plt.xlabel('假警報率')plt.ylabel('識別率')plt.title('多分類模型的ROC曲線')plt.rcParams['font.sans-serif'] = ['SimHei']plt.legend(loc='lower right')
?if save_path:plt.savefig(save_path)print(f" ROC曲線已保存到 {save_path}")else:plt.show()

3.2 構建深層神經網絡模型(第六周)

構建 10 層 BP 神經網絡模型

該BP網絡結構包括:

  • 輸入層:將圖像展平為一維向量,輸入維度默認為 784,對應于 28×28 的灰度圖(如 MNIST)。

  • 隱藏層:通過參數 num_layers=10 指定總層數,其中 hidden_size=128 表示每層的神經元數量,采用了 8 個中間隱藏層(10 層結構 = 輸入層 + 8 個隱藏層 + 輸出層),并使用 ReLU 激活函數進行非線性變換。

  • 輸出層:將最后一層的輸出映射到 num_classes=10,用于10類分類任務。

class DeepBPNet(nn.Module):def __init__(self, input_size=784, hidden_size=128, num_classes=10, num_layers=10, init_method='xavier'):super(DeepBPNet, self).__init__()assert num_layers >= 2, "網絡層數必須 >= 2"self.input_layer = nn.Linear(input_size, hidden_size)self.hidden_layers = nn.ModuleList([nn.Linear(hidden_size, hidden_size) for _ in range(num_layers - 2)])self.output_layer = nn.Linear(hidden_size, num_classes)self.init_weights(method=init_method)
?def forward(self, x):x = x.view(x.size(0), -1)x = F.relu(self.input_layer(x))for layer in self.hidden_layers:x = F.relu(layer(x))x = self.output_layer(x)return x

3.3 構建卷積神經網絡模型(第七周)

構建 3 層 CNN 神經網絡模型

本模塊主要通過構建一個可配置的卷積神經網絡(CustomCNN 類)實現圖像分類任務,其核心思路是:利用多層卷積層、激活函數和池化操作提取圖像特征,隨后通過全連接層完成分類預測。

該 CNN 網絡結構包括以下部分:

  • 輸入層:接收尺寸為 28×28 的灰度圖像,輸入通道默認為 1(適用于 MNIST),也支持自定義為彩色圖像的 3 通道(如 CIFAR-10)。

  • 卷積模塊:通過參數 conv_layers=3 控制卷積層數,每層包含一個 3×3 的卷積核(padding=1 保持尺寸)、激活函數(如 ReLUTanh 等)以及 2×2 的最大池化操作(MaxPool2d),用于特征提取與降維。每一層的通道數由 base_channels=162^i 級數增長,即為 16 → 32 → 64

  • 全連接層:卷積模塊輸出展平后,通過兩個線性全連接層處理。第一層映射到 128 個神經元,第二層輸出 num_classes=10,用于多分類任務。

  • 激活函數與初始化:激活函數可選(如 ReLUSigmoid 等),通過參數 activation 控制;所有卷積層與線性層的權重初始化方式也可配置(如 xavierkaiming 等),增強模型靈活性與實驗可控性。

class CustomCNN(nn.Module):def __init__(self, in_channels=1, num_classes=10, conv_layers=3, base_channels=16, activation='relu', init_method='xavier'):super(CustomCNN, self).__init__()assert conv_layers >= 1, "至少要有一個卷積層"self.activation_name = activationself.activation_fn = self._get_activation_fn(activation)self.conv_blocks = nn.ModuleList()channels = in_channelsfor i in range(conv_layers):out_channels = base_channels * (2 ** i)self.conv_blocks.append(nn.Sequential(nn.Conv2d(channels, out_channels, kernel_size=3, padding=1),self.activation_fn,nn.MaxPool2d(2, 2)))channels = out_channelsdummy_input = torch.zeros(1, in_channels, 28, 28)with torch.no_grad():for layer in self.conv_blocks:dummy_input = layer(dummy_input)flatten_dim = dummy_input.view(1, -1).shape[1]self.fc1 = nn.Linear(flatten_dim, 128)self.fc2 = nn.Linear(128, num_classes)self.init_weights(init_method)
?def forward(self, x):for layer in self.conv_blocks:x = layer(x)x = x.view(x.size(0), -1)x = self.activation_fn(self.fc1(x))x = self.fc2(x)return x

四、實驗設計

4.1 數據集及數據集劃分方式

MNIST 數據集:包含 70,000 張 28×28 像素的灰度手寫數字圖片,共 10 個類別(0~9)。本實驗使用其中的 訓練集部分(60,000 張)作為訓練與驗證數據。

CIFAR-10 數據集:包含 60,000 張 32×32 像素的彩色圖像,分為 10 個類別,如飛機、汽車、貓、狗等。實驗中使用其中的訓練集部分(50,000 張)進行模型訓練與評估。

為了更穩定且全面地評估模型性能,本實驗采用了K 折交叉驗證法(K-Fold Cross Validation)。我們將訓練集劃分為 5 份(k=5),每次選取其中一份作為驗證集,其余部分用于訓練,重復 5 次后計算每折的準確率與損失,并求取平均值,減小隨機性影響,使結果更具參考價值。

4.2 實驗選用的超參數

BP選用的超參數:
  • 初始化方式:Xavier / Kaiming / Normal / Uniform

  • 神經元個數:64、128、256、512

  • 網絡層數:3、5、10、20

  • 激活函數:ReLU / LeakyReLU / Sigmoid / Tanh

CNN選用的超參數:
  • 初始化方式:Xavier / Kaiming / Normal / Uniform

  • 卷積核個數:8、16、32、64

  • 卷積層數:1、2、3、4

  • 激活函數:ReLU / LeakyReLU / Sigmoid / Tanh

五、實驗結果展示與分析

5.1 對比圖表

BPNet vs CNN 性能對比(進行完優化的對比圖表)
模型類型數據集最佳準確率最低損失最優配置簡述
BPNetMNIST0.95750.1391Xavier 128 3 ReLU
BPNetCIFAR-100.43891.5870Xavier 128 3 ReLU
CNNMNIST0.98530.0474Xavier 64 3 LeakyReLU
CNNCIFAR-100.56471.2114Kaiming 64 3 tanh

5.2 改變模型超參數

BP更換不同模塊參數以探明作用:
  • 初始化方式:Xavier / Kaiming / Normal / Uniform

  • 神經元個數:64、128、256、512

  • 網絡層數:3、5、10、20

  • 激活函數:ReLU / LeakyReLU / Sigmoid / Tanh

MINST

為了探究網絡結構各項參數對模型性能的影響,我們在MNIST數據集上通過更改初始化方式神經元個數網絡層數激活函數,對BP神經網絡模型進行了系統性對比實驗。

初始化方式對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier12810ReLU0.94640.1807
Kaiming12810ReLU0.94440.1896
Normal12810ReLU0.73690.7285
Uniform12810ReLU0.93580.2252

最優選擇:Xavier 初始化

表明對于BP神經網絡而言,權重初始化方式對訓練過程收斂速度和最終性能具有顯著影響。Xavier初始化能夠保持每層輸出的方差一致,避免梯度消失或爆炸,從而提升訓練穩定性。Normal初始化可能導致初始權重偏離過大,造成梯度傳播困難。

神經元個數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier6410ReLU0.93890.2074
Xavier12810ReLU0.94640.1807
Xavier25610ReLU0.94970.1939
Xavier51210ReLU0.94210.2356

最佳神經元數量:256

實驗發現,當神經元個數為 256 時,模型準確率達到最高(94.97%)。繼續增大至512時,反而略有下降,說明神經元過多可能導致參數冗余,從而出現過擬合或訓練不穩定。

網絡層數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier1283ReLU0.95750.1391
Xavier1285ReLU0.95280.1506
Xavier12810ReLU0.94640.1807
Xavier12820ReLU0.90130.3571

最佳網絡層數:3層

實驗比較了 3、5、10、20 層的BP神經網絡,發現3層網絡的性能反而最好,準確率為 95.75%,而層數越多,效果反而逐漸下降,尤其在20層時準確率驟降至 90.13%,且Loss顯著增大。

這說明對于結構簡單的MNIST圖像識別任務而言,過深的網絡不僅不能提升表現,反而可能因為梯度消失或過擬合而降低性能。合理控制網絡深度有助于模型的高效訓練。

激活函數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier12810ReLU0.94640.1807
Xavier12810LeakyReLU0.94720.1801
Xavier12810Sigmoid0.38301.4522
Xavier12810Tanh0.94230.1984

最佳激活函數:LeakyReLU

在激活函數對比中,LeakyReLU略優于ReLU,表現為更低的Loss與更高的Accuracy。Tanh次之,而Sigmoid表現最差,準確率僅為38.30%,幾乎無法完成任務。

CIFAR-10
初始化方式對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier12810ReLU0.40991.6549
Kaiming12810ReLU0.38761.7094
Normal12810ReLU0.17032.0517
Uniform12810ReLU0.32091.7992

最優選擇:Xavier 初始化

Xavier 初始化適用于對稱激活函數(如 ReLU、Tanh),其在淺層到中等深度的網絡結構中表現穩定。相比之下,Normal 初始化不具備前向信號的控制能力,容易導致梯度消失或爆炸,效果最差。

神經元個數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier6410ReLU0.40081.6731
Xavier12810ReLU0.40991.6549
Xavier25610ReLU0.40861.656
Xavier51210ReLU0.38931.7147

最佳神經元數量:128

進一步增加神經元并未帶來顯著提升,反而可能引起過擬合。

網絡層數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier1283ReLU0.43891.5870
Xavier1285ReLU0.43571.5930
Xavier12810ReLU0.40991.6549
Xavier12820ReLU0.22541.9535

最佳網絡層數:3層

深層全連接網絡在缺乏卷積提取能力的前提下,面對復雜圖像如 CIFAR-10 會迅速增加訓練難度,出現訓練不穩定、梯度消失等問題。而淺層結構能更快地捕捉全局特征,反而帶來更優表現。

激活函數對比表
初始化方式神經元個數網絡層數激活函數AccuracyLoss
Xavier12810ReLU0.40991.6549
Xavier12810LeakyReLU0.41301.6456
Xavier12810Sigmoid0.15882.0878
Xavier12810Tanh0.37571.7548

最佳激活函數:LeakyReLU

LeakyReLU 在負區間仍保留微弱梯度,避免了神經元“失活”;但實際使用時,依然使用了ReLU測試數據。

CNN更換不同模塊參數以探明作用:
  • 初始化方式:Xavier / Kaiming / Normal / Uniform

  • 卷積核個數:8、16、32、64

  • 卷積層數:1、2、3、4

  • 激活函數:ReLU / LeakyReLU / Sigmoid / Tanh

MNIST
初始化方式對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier163ReLU0.97990.0637
Kaiming163ReLU0.97760.0742
Normal163ReLU0.96580.1085
Uniform163ReLU0.97800.0713

Xavier > Uniform > Kaiming > Normal

最佳初始化方式:Xavier

從準確率與損失函數表現來看,Xavier 初始化以 0.9799 的 Accuracy 和 0.0637 的 Loss 表現最佳,說明其在權重初始化時有更好的穩定性與收斂效果。

卷積核個數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier83ReLU0.97990.0637
Xavier163ReLU0.97280.0871
Xavier323ReLU0.98030.0621
Xavier643ReLU0.98420.0495

64 > 32 > 8 ≈ 16

最佳卷積核個數:64

卷積核個數從 8 到 64 呈現出較強的正向趨勢,64 個卷積核時準確率最高,達到了 0.9842,且 Loss 最低,僅為 0.0495,說明在該任務中更豐富的卷積特征表達有助于提升分類性能。

卷積層數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier161ReLU0.97290.0905
Xavier162ReLU0.97680.754
Xavier163ReLU0.97990.0637
Xavier164ReLU0.97520.0810

3 層 > 2 層 > 4 層 > 1 層

最佳卷積層數:3 層

卷積層數增加到 3 層時模型性能最優,再往上反而性能下降。這表明在 MNIST 這種簡單數據集上,過深的網絡并不一定帶來提升,反而可能導致特征過擬合或訓練困難。

激活函數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier163ReLU0.97990.0637
Xavier163LeakyReLU0.98200.0580
Xavier163Sigmoid0.92870.2467
Xavier163Tanh0.97970.0649

LeakyReLU > ReLU ≈ Tanh > Sigmoid

最佳激活函數:LeakyReLU

在所有激活函數中,LeakyReLU 以 0.9820 的 Accuracy 和 0.0580 的 Loss 表現最優,略優于 ReLU,說明其在處理 ReLU 的“神經元死亡問題”方面更具優勢。Sigmoid 明顯不適合 CNN,收斂慢且梯度消失,效果最差。

CIFAR-10
初始化方式對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier163ReLU0.56851.2097
Kaiming163ReLU0.57621.2068
Normal163ReLU0.46121.4741
Uniform163ReLU0.54631.2650

Kaiming>Xavier > Uniform > Normal

推薦初始化方式:Kaiming

卷積核個數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier83ReLU0.50831.3704
Xavier163ReLU0.56851.2097
Xavier323ReLU0.61101.0978
Xavier643ReLU0.64071.0130

64>32>16>8

最佳卷積核個數:64

卷積層數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier161ReLU0.55561.2541
Xavier162ReLU0.56301.2301
Xavier163ReLU0.56851.2097
Xavier164ReLU0.54001.241

3 層 > 2 層 > 1層 > 4 層

最佳卷積層數:3 層

依然是在底層到高層數表現為先增長,后減少,存在最優層數,避免過擬合的同時,又存在較好結果。

激活函數對比表
初始化方式卷積核個數卷積層數激活函數AccuracyLoss
Xavier163ReLU0.56851.2097
Xavier163LeakyReLU0.58441.1684
Xavier163Sigmoid0.31491.1278
Xavier163Tanh0.60461.8902

Tanh>LeakyReLU > ReLU> Sigmoid

最佳激活函數:Tanh

Tanh中心對稱的性質可能使得數據分布更加居中,有助于緩解梯度消失問題,從而在這個更大數據集,可能相對優勢較大。

5.3 結果分析

在前面的參數對比實驗中,分別找出了初始化方式、激活函數、神經元個數和網絡層數的“單項最優配置”,期望它們的組合能夠帶來“最優整體性能”。然而,組合結果卻略低于部分單項測試下的最佳結果(如3層網絡+ReLU時Accuracy達到了 0.9575,而最終組合結果為 0.9557),這說明最佳參數并非簡單疊加得出。

原因分析:

參數間存在依賴與耦合:多個參數組合在一起時,其交互效應可能會導致性能打折扣。

淺層網絡限制了其他參數的潛力:3層網絡作為最優層數,這是在保持訓練簡單的基礎上表現最好的結構,但它可能無法充分發揮復雜初始化(如Xavier)或激活函數(如LeakyReLU)帶來的優勢。

超參數之間存在“過擬合風險疊加”:雖然每個參數單獨設置下不會引發過擬合,但組合在一起時,可能出現過度表達能力,導致在驗證集上性能下降,尤其是Loss值升高。

因此最終仍然選擇Xavier 128 3 ReLU作為MNIST數據集最優配置。

同樣,在實驗中,依然嘗試將所有在單項實驗中表現最優的超參數組合起來,形成“綜合最優配置”,但實際上依然不如之前的測試結果,因此最終仍然選擇Xavier 128 3 ReLU作為MNIST數據集最優配置。

本次結果發現,綜合采用各參數單項調優中表現最優的配置,即 Xavier 初始化、LeakyReLU 激活函數、3 層卷積結構以及64個基礎卷積核,最終模型在 MNIST 數據集上取得了 0.9853 的平均準確率和 0.0474 的平均損失。但實際并非是組合起來的提升,因為我們看到這與所謂的”單項冠軍“(Xavier 初始化、ReLU 激活函數、3 層卷積結構以及64個基礎卷積核)只相差了激活函數,因此這項結論本質上還是單項的勝利,而非結合的結果。

在本次CNN模型訓練CIFAR-10數據集中,成功取得綜合最優的體現,通過枚舉的方法,最終采用 Kaiming 初始化、Tanh 激活函數、3 層卷積結構以及卷積核基數為 64 的 CNN 模型在 CIFAR-10 數據集上取得了最佳性能,平均準確率達到 0.5647,損失值為 1.2114,相較于其他配置均有明顯優勢。

后經查詢分析,得到原因可能如下:這一組合能夠充分利用 Kaiming 初始化在深度網絡中對梯度穩定的優化效果,同時 Tanh 激活函數在 CIFAR-10 這類自然圖像數據上展現出更強的非線性表達能力和穩定性,配合較深且足夠寬的網絡結構,有助于提取更豐富的圖像特征,從而在分類任務中表現更優。

六、實驗結論

在本次實驗中,我們系統性地掌握了深度學習模型的編程實現過程,包括如何使用 PyTorch 框架加載標準圖像數據集(MNIST 與 CIFAR-10)、構建可配置的神經網絡模型(BP 與 CNN)、執行 K 折交叉驗證訓練模型,以及如何靈活調整網絡結構參數以優化模型性能。

通過本次實驗,也加深了對超參數在模型訓練中的影響的理解,我們觀察到模型表現受初始化方式、激活函數、網絡層數和神經元/卷積核數量等多個因素的影響,并非所有參數的“最優”組合都能帶來“最優”的整體結果,說明它們之間存在復雜的相互作用和依賴關系。尤其是在淺層網絡中,部分復雜配置的優勢無法完全體現,甚至可能因參數冗余導致性能下降。

在未來的研究中,測試更多的可能數據,嘗試更多的橫向對比,同時進行更多的組合,但由于本次實驗數據量和訓練時間的限制(如果全部測出,會跑4^5=1024次代碼),我們未能進行更大規模的實驗;此外,還可以嘗試引入參數敏感性分析或可視化方法,更量化地評估各超參數對模型性能的貢獻,從而實現更高效、自動化的模型調優。

本次實驗不僅提升了我們對深度學習模型的工程實踐能力,也幫助我們理解了人工智能模型在海量數據中的構建與優化思路。這為以后進行海洋數據分析和處理,提供了很大的幫助!

七、實驗數據與代碼

實驗源代碼

?
import torch
import torch.nn as nn
import torch.nn.functional as F
from torchvision import datasets, transforms
from torch.utils.data import DataLoader, Subset
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score, log_loss, roc_curve, auc
from sklearn.preprocessing import label_binarize
import matplotlib.pyplot as plt
import numpy as np
?
# ========== 設置隨機種子 ==========
seed = 42
torch.manual_seed(seed)
np.random.seed(seed)
?
# ========== 參數配置 ==========
k_folds = 5
batch_size = 64
use_mnist = True
model_type = 'cnn'
epochs = 1
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
?
# ========== 模型定義 ==========
class DeepBPNet(nn.Module):def __init__(self, input_size=784, hidden_size=128, num_classes=10, num_layers=10, activation='relu', init_method='xavier'):super(DeepBPNet, self).__init__()assert num_layers >= 2, "網絡層數必須 >= 2"self.activation_fn = self._get_activation_fn(activation)self.input_layer = nn.Linear(input_size, hidden_size)self.hidden_layers = nn.ModuleList([nn.Linear(hidden_size, hidden_size) for _ in range(num_layers - 2)])self.output_layer = nn.Linear(hidden_size, num_classes)self.init_weights(method=init_method)
?def forward(self, x):x = x.view(x.size(0), -1)x = self.activation_fn(self.input_layer(x))for layer in self.hidden_layers:x = self.activation_fn(layer(x))x = self.output_layer(x)return x
?def _get_activation_fn(self, name):return {'relu': nn.ReLU(),'tanh': nn.Tanh(),'sigmoid': nn.Sigmoid(),'leaky_relu': nn.LeakyReLU(0.1)}.get(name.lower(), nn.ReLU())
?def init_weights(self, method='xavier'):for m in self.modules():if isinstance(m, nn.Linear):if method == 'xavier':nn.init.xavier_uniform_(m.weight)elif method == 'kaiming':nn.init.kaiming_normal_(m.weight, nonlinearity='relu')elif method == 'normal':nn.init.normal_(m.weight, mean=0.0, std=0.02)elif method == 'uniform':nn.init.uniform_(m.weight, a=-0.1, b=0.1)if m.bias is not None:nn.init.zeros_(m.bias)
?
class CustomCNN(nn.Module):def __init__(self, in_channels=1, input_size=(28,28), num_classes=10, conv_layers=3, base_channels=16, activation='relu', init_method='xavier'):super(CustomCNN, self).__init__()assert conv_layers >= 1, "至少要有一個卷積層"self.activation_fn = self._get_activation_fn(activation)self.conv_blocks = nn.ModuleList()channels = in_channels
?for i in range(conv_layers):out_channels = base_channels * (2 ** i)self.conv_blocks.append(nn.Sequential(nn.Conv2d(channels, out_channels, kernel_size=3, padding=1),self.activation_fn,nn.MaxPool2d(2, 2)))channels = out_channels
?dummy_input = torch.zeros(1, in_channels, *input_size)with torch.no_grad():for layer in self.conv_blocks:dummy_input = layer(dummy_input)flatten_dim = dummy_input.view(1, -1).shape[1]
?self.fc1 = nn.Linear(flatten_dim, 128)self.fc2 = nn.Linear(128, num_classes)self.init_weights(init_method)
?def forward(self, x):for layer in self.conv_blocks:x = layer(x)x = x.view(x.size(0), -1)x = self.activation_fn(self.fc1(x))x = self.fc2(x)return x
?def _get_activation_fn(self, name):return {'relu': nn.ReLU(),'tanh': nn.Tanh(),'sigmoid': nn.Sigmoid(),'leaky_relu': nn.LeakyReLU(0.1)}.get(name.lower(), nn.ReLU())
?def init_weights(self, method='xavier'):for m in self.modules():if isinstance(m, (nn.Conv2d, nn.Linear)):if method == 'xavier':nn.init.xavier_uniform_(m.weight)elif method == 'kaiming':nn.init.kaiming_normal_(m.weight, nonlinearity='relu')elif method == 'normal':nn.init.normal_(m.weight, mean=0.0, std=0.02)elif method == 'uniform':nn.init.uniform_(m.weight, a=-0.1, b=0.1)if m.bias is not None:nn.init.zeros_(m.bias)
?
# ========== 數據讀取與預處理模塊 ==========
def load_dataset(use_mnist=True):if use_mnist:transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.1307,), (0.3081,))])dataset = datasets.MNIST(root='./data', train=True, download=True, transform=transform)else:transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.5,), (0.5,))])dataset = datasets.CIFAR10(root='./data', train=True, download=True, transform=transform)print(f"加載數據集完成:{len(dataset)}張圖像,尺寸為 {dataset[0][0].shape}")return dataset
?
# ========== 數據與模型接口 ==========
def get_model(model_type='bp', input_shape=(1, 28, 28), num_classes=10, **kwargs):if model_type == 'bp':input_size = np.prod(input_shape)return DeepBPNet(input_size=input_size, num_classes=num_classes, **kwargs)elif model_type == 'cnn':return CustomCNN(in_channels=input_shape[0], input_size=input_shape[1:], num_classes=num_classes, **kwargs)else:raise ValueError("模型必須是'bp'或者'cnn'")
?
?
?
# ========== 模型評估模塊 ==========
def evaluate_model_kfold(dataset, model_type='cnn', k_folds=5, batch_size=64, num_classes=10, device=None, epochs=1, **kwargs):if device is None:device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
?indices = list(range(len(dataset)))kf = KFold(n_splits=k_folds, shuffle=True, random_state=42)
?all_fold_metrics = []all_probs = []all_targets = []
?for fold, (train_idx, val_idx) in enumerate(kf.split(indices)):print(f"\n 訓練輪數 {fold + 1}/{k_folds}")
?train_subset = Subset(dataset, train_idx)val_subset = Subset(dataset, val_idx)train_loader = DataLoader(train_subset, batch_size=batch_size, shuffle=True)val_loader = DataLoader(val_subset, batch_size=batch_size, shuffle=False)
?sample_input, _ = next(iter(train_loader))model = get_model(model_type=model_type,input_shape=sample_input.shape[1:],num_classes=num_classes,**kwargs).to(device)
?criterion = nn.CrossEntropyLoss()optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
?# === 訓練階段 ===model.train()for epoch in range(epochs):for inputs, labels in train_loader:inputs, labels = inputs.to(device), labels.to(device)optimizer.zero_grad()outputs = model(inputs)loss = criterion(outputs, labels)loss.backward()optimizer.step()
?# === 驗證階段 ===model.eval()y_true, y_pred, y_prob = [], [], []
?with torch.no_grad():for inputs, labels in val_loader:inputs, labels = inputs.to(device), labels.to(device)outputs = model(inputs)probs = F.softmax(outputs, dim=1)preds = torch.argmax(probs, dim=1)
?y_true.extend(labels.cpu().numpy())y_pred.extend(preds.cpu().numpy())y_prob.extend(probs.cpu().numpy())
?acc = accuracy_score(y_true, y_pred)loss = log_loss(y_true, y_prob, labels=list(range(num_classes)))
?all_fold_metrics.append({'fold': fold + 1, 'accuracy': acc, 'loss': loss})all_probs.extend(y_prob)all_targets.extend(y_true)
?print(f" Fold {fold + 1} Accuracy: {acc:.4f}, Loss: {loss:.4f}")
?return all_fold_metrics, np.array(all_probs), np.array(all_targets)
?
?
# ========== 模型評估可視化模塊 ==========
def plot_multiclass_roc(probs, targets, num_classes, save_path=None):targets_onehot = label_binarize(targets, classes=list(range(num_classes)))
?fpr = dict()tpr = dict()roc_auc = dict()
?for i in range(num_classes):fpr[i], tpr[i], _ = roc_curve(targets_onehot[:, i], probs[:, i])roc_auc[i] = auc(fpr[i], tpr[i])
?plt.figure(figsize=(10, 8))for i in range(num_classes):plt.plot(fpr[i], tpr[i], label=f"Class {i} (AUC = {roc_auc[i]:.2f})")
?plt.plot([0, 1], [0, 1], 'k--', label='Random')plt.xlim([0.0, 1.0])plt.ylim([0.95, 1.05])plt.xlabel('假警報率')plt.ylabel('識別率')plt.title('多分類模型的ROC曲線')plt.rcParams['font.sans-serif'] = ['SimHei']plt.legend(loc='lower right')
?if save_path:plt.savefig(save_path)print(f" ROC曲線已保存到 {save_path}")else:plt.show()
?
?
?
# ========== 主程序入口 ==========
if __name__ == '__main__':# === 數據集選擇 ===print("請選擇數據集:")print("1 - MNIST")print("2 - CIFAR-10")dataset_choice = input("請輸入選項(1 或 2):").strip()if dataset_choice == '1':use_mnist = Trueelif dataset_choice == '2':use_mnist = Falseelse:print("無效輸入,默認使用 MNIST")use_mnist = True
?# === 模型結構選擇 ===print("\n請選擇模型結構:")print("1 - CNN(卷積神經網絡)")print("2 - BPNet(多層感知機)")model_choice = input("請輸入選項(1 或 2):").strip()if model_choice == '1':model_type = 'cnn'elif model_choice == '2':model_type = 'bp'else:print("無效輸入,默認使用 CNN")model_type = 'cnn'
?# === 初始化方式選擇 ===print("\n請選擇初始化方式:")print("1 - Xavier(推薦)")print("2 - Kaiming")print("3 - Normal")print("4 - Uniform")init_choice = input("請輸入選項(1~4):").strip()init_method = {'1': 'xavier','2': 'kaiming','3': 'normal','4': 'uniform'}.get(init_choice, 'xavier')if init_choice not in ['1', '2', '3', '4']:print("無效輸入,默認使用 Xavier 初始化")
?# === 激活函數選擇 ===print("\n請選擇激活函數:")print("1 - ReLU")print("2 - LeakyReLU")print("3 - Tanh")print("4 - Sigmoid")act_choice = input("請輸入選項(1~4):").strip()activation = {'1': 'relu','2': 'leaky_relu','3': 'tanh','4': 'sigmoid'}.get(act_choice, 'relu')if act_choice not in ['1', '2', '3', '4']:print("無效輸入,默認使用 ReLU 激活函數")
?# === 網絡結構參數(根據模型類型設置) ===extra_args = {}if model_type == 'bp':hidden_size = input("\n請輸入每層的神經元數量(默認128):").strip()num_layers = input("請輸入網絡層數(最少2層,默認10):").strip()extra_args['hidden_size'] = int(hidden_size) if hidden_size.isdigit() else 128extra_args['num_layers'] = int(num_layers) if num_layers.isdigit() else 10# 將激活函數傳遞給BP網絡extra_args['activation'] = activationelif model_type == 'cnn':conv_layers = input("\n請輸入卷積層數(默認3):").strip()base_channels = input("請輸入基礎卷積核個數(默認16):").strip()extra_args['conv_layers'] = int(conv_layers) if conv_layers.isdigit() else 3extra_args['base_channels'] = int(base_channels) if base_channels.isdigit() else 16extra_args['activation'] = activation
?extra_args['init_method'] = init_method
?# === 加載數據 & 開始訓練 ===dataset = load_dataset(use_mnist=use_mnist)metrics, probs, targets = evaluate_model_kfold(dataset=dataset,model_type=model_type,k_folds=k_folds,batch_size=batch_size,num_classes=10,device=device,epochs=epochs,**extra_args ?# 💡傳入模型構建參數)
?print("\n 每折評估結果:")for result in metrics:print(f"Fold {result['fold']} - Accuracy: {result['accuracy']:.4f}, Loss: {result['loss']:.4f}")
?# === 繪制 ROC 曲線圖 ===plot_multiclass_roc(probs=probs, targets=targets, num_classes=10)
?# === 輸出整體實驗配置信息和平均結果 ===avg_acc = np.mean([fold['accuracy'] for fold in metrics])avg_loss = np.mean([fold['loss'] for fold in metrics])
?print("\n 實驗配置與結果匯總:")print(f"數據集 ? ? ? ? :{'MNIST' if use_mnist else 'CIFAR-10'}")print(f"模型結構 ? ? ? :{'BPNet' if model_type == 'bp' else 'CNN'}")print(f"初始化方式 ? ? :{init_method}")if model_type == 'cnn':print(f"激活函數 ? ? ? :{activation}")print(f"卷積層數 ? ? ? :{extra_args['conv_layers']}")print(f"卷積核基數 ? ? :{extra_args['base_channels']}")else:print(f"激活函數 ? ? ? :{activation}")print(f"神經元數量 ? ? :{extra_args['hidden_size']}")print(f"網絡層數 ? ? ? :{extra_args['num_layers']}")
?print(f"\n 平均 Accuracy:{avg_acc:.4f}")print(f" 平均 Loss ?  :{avg_loss:.4f}")
?
?
?
?

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/918304.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/918304.shtml
英文地址,請注明出處:http://en.pswp.cn/news/918304.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

HarmonyOS應用開發-低代碼開發登錄頁面(超詳細)

本篇文章我來手把手教大家做一個HarmonyOS 應用的登錄頁面,逐步講解,非常細致,百分百能學會,并提供全部源碼。頁面使用 DevEco Studio 的低代碼開發。 通過本文的實踐經驗,我想告訴大家, HarmonyOS 應用開發…

AJAX與axios框架

文章目錄前言案例跨域訪問總結?前言 提示:這里可以添加本文要記錄的大概內容: 通過 ajax 進行前后端交互 案例 此項目用到了javaweb知識 首先創建JavaWeb項目編寫代碼: package ajax;import java.io.IOException; import java.util.Arr…

智能創造的幕后推手:AIGC浪潮下看AI訓練師如何塑造智能未來

文章目錄一、AIGC時代的算法與模型訓練概覽二、算法與模型訓練的關鍵環節三、AI訓練師的角色與職責四、AI訓練師的專業技能與素養五、AIGC算法與模型訓練的未來展望《AI訓練師手冊:算法與模型訓練從入門到精通》亮點內容簡介作者簡介谷建陽目錄《醫學統計學從入門到…

Python設計模式 - 裝飾模式

定義 裝飾模式(Decorator Pattern)是一種結構型設計模式,用于在不修改原有類的情況下動態地擴展對象的功能。 結構抽象組件(Component):定義對象的公共接口,使得客戶端能以一致的方式處理未被裝…

MySQL(188)如何使用MySQL的慢查詢工具?

使用MySQL的慢查詢工具可以幫助開發者識別和優化性能不佳的SQL查詢。以下是詳細深入的步驟和代碼示例,幫助你使用MySQL的慢查詢工具來進行查詢分析和優化。 一、啟用慢查詢日志 首先,你需要確保MySQL的慢查詢日志功能是啟用的。慢查詢日志記錄了所有執行…

如何培養自己工程化的能力(python項目)

培養 Python 項目的工程化能力需要系統性訓練,以下從基礎到高階的實踐路徑,結合具體案例和工具鏈,幫助你逐步進階:一、夯實工程化基礎能力?1. 規范代碼與項目結構??項目模板化?使用 cookiecutter生成標準項目結構,…

AI編程插件對比分析:CodeRider、GitHub Copilot及其他

AI編程插件對比分析:CodeRider、GitHub Copilot及其他 隨著人工智能技術的快速發展,AI編程插件已成為提升開發者生產力的重要工具。CodeRider和GitHub Copilot作為市場上的領先者,分別以其獨特的特性和生態系統吸引了大量開發者。本文將從功能特性、性能表現、集成性、用戶…

uniapp/uniappx實現圖片或視頻文件選擇時同步告知權限申請目的解決華為等應用市場上架審核問題

在UNIAPP支持vue和nvue,在UNIAPPX支持uvue,安卓支持在選擇圖片或視頻文件權限申請的時候自動同步告知權限申請目的。輕松解決在華為應用市場審核,要求告知權限申請目的或說明的問題。 UNIAPP相冊圖片視頻選擇器(安卓可以自定義界面樣式)功能介紹&#x…

jupyter notebook如何打開其他盤目錄

問題描述Jupyter Notebook 相信是我們學習 Python 避不開的一個工具。當我們使用 pip install notebook 安裝 Notebook 之后,使用命令 jupyter notebook 啟動服務,啟動之后默認會在瀏覽器打開界面。我們會發現,這個界面默認在 C 盤下&#xf…

C語言深度剖析

一、關鍵字 1.1 最快的關鍵字-register register 這個關鍵字請求編譯器盡可能將變量存在CPU內部寄存器中,而不是通過內存尋址以提高效率。 注意是:盡可能、而不是絕對 1.1.1 皇帝身邊的小太監-寄存器 不知道什么是寄存器,那見過太監沒有其實寄存器就是相當于。一個cpu的…

電腦使用“碎片整理”程序的作用

1.解決文件碎片化問題碎片整理的作用:將這些分散的文件片段重新整理、拼接,使其連續存儲在硬盤的某個區域,減少文件的 “碎片化” 程度。2. 提升硬盤讀寫速度機械硬盤的特殊性:機械硬盤依賴磁頭的物理移動來讀取數據,若…

AI 軟件工程開發 AI 算法 架構與業務

AI 軟件工程開發 & AI 算法 & 架構與業務前言1.AI 軟件工程開發1.1. AI Developer Studio (playground級)1.2. Agent & RAG1.3. LangChain & LangGraph1.4. MCP, Model Context Protocol1.5. Ollama1.6. Coze & Dify2.AI 算法2.1. G…

uniapp實現的圓形滾盤組件模板

采用 uniapp 實現的一款圓形滾盤示例組件模板, 支持 vue2、vue3,適配H5、微信小程序(其他小程序未試過,可自行嘗試) 代碼實現簡約易懂,用戶可根據自身需求下載模板,并進行擴展開發可到插件市場下載嘗試&…

無須炮解,打開即是Pro版

聊一聊 文檔或文件轉圖片,這個我有段時間沒有推薦了。 今天發現了一款非常好用的圖像格式轉換編輯軟件。 有需要的小伙伴請及時收藏,防止下次找不到。 軟件介紹 全能圖像格式轉換工具 這是一款全能的圖像轉換軟件,支持幾乎所有的圖像格式…

企業高性能web服務器——Nginx

Nginx介紹 Nginx是一個高性能的HTTP和反向代理服務器,也是一個郵件代理服務器。由俄羅斯的程序設計師Igor Sysoev所開發,官方測試nginx能夠支撐5萬并發鏈接,并且cpu、內存等資源消耗卻非常低,運行非常穩定。所以其特點是占有內存…

MCU控制ADAU1701,用System Workbench for STM32導入工程

作者的話 MCU控制ADAU1701,我有寫一個文檔詳細講步驟,里頭用到了System Workbench for STM32這個軟件,他是基于eclips內核的開發軟件,一般來講,設置好workspce工程就會出來,但是架不住就有設置好工程不出來…

SQL176 每個題目和每份試卷被作答的人數和次數

描述現有試卷作答記錄表exam_record(uid用戶ID, exam_id試卷ID, start_time開始作答時間, submit_time交卷時間, score得分):iduidexam_idstart_timesubmit_timescore1100190012021-09-01 09:01:012021-09-01 09:41:01812100290022021-09-01 …

構建第三方軟件倉庫

1 下載第三方軟件到指定目錄[rootServer_b ~]# mkdir software [rootServer_b software]# wget https://dldir1v6.qq.com/qqfile/qq/QQNT/Linux/QQ_3.2.18_250724_x86_64_01.rpm2 安裝軟件信息采集工具[rootServer_b software]# yum install createrepo -y [rootServer_b softw…

Linux 管道命令及相關命令練習與 Shell 編程、Tomcat 安裝

2.實驗目的掌握 Linux 管道命令及相關命令(cut、sort、wc、uniq、tee、tr、split)的使用方法。學會使用 Shell 編程實現基本的計算器功能。掌握在 CentOS 7 系統中安裝 Tomcat 的方法。實驗內容1. Linux 管道命令及相關命令練習1.1 管道命令定義&#xf…

藍牙基礎:FIFO(First-In-First-Out)緩存區

在藍牙通信中,FIFO(First-In-First-Out,先進先出)緩存區是解決數據傳輸中“速度不匹配”和“時序異步”問題的核心機制,廣泛應用于藍牙芯片內部、協議棧各層級及主從設備交互中。其核心作用是臨時存儲數據,…