深度學習-全連接神經網絡2

六、反向傳播算法

反向傳播(Back Propagation,簡稱BP)算法是用于訓練神經網絡的核心算法之一,它通過計算損失函數(如均方誤差或交叉熵)相對于每個權重參數的梯度,來優化神經網絡的權重。

1、前向傳播

前向傳播(Forward Propagation)把輸入數據經過各層神經元的運算并逐層向前傳輸,一直到輸出層為止。

1.1數學表達

下面是一個簡單的三層神經網絡(輸入層、隱藏層、輸出層)前向傳播的基本步驟分析。

  • 輸入層到隱藏層

給定輸入 x 和權重矩陣 W1 及偏置向量 b1,隱藏層的輸出(激活值)計算如下:

將z^(1)?通過激活函數 σ進行激活:

  • 隱藏層到輸出層

隱藏層的輸出 a^(1)?通過輸出層的權重矩陣 W2和偏置 b2 生成最終的輸出:

輸出層的激活值 a^(2)?是最終的預測結果:

1.2作用

前向傳播的主要作用是:

  1. 計算神經網絡的輸出結果,用于預測或計算損失。

  2. 在反向傳播中使用,通過計算損失函數相對于每個參數的梯度來優化網絡。

2、BP基礎之梯度下降算法

梯度下降算法的目標是找到使損失函數 L(θ) 最小的參數θ,其核心是沿著損失函數梯度的負方向更新參數,以逐步逼近局部或全局最優解,從而使模型更好地擬合訓練數據。

2.1數學描述

數學公式:

其中,α是學習率:

  • 學習率太小,每次訓練之后的效果太小,增加時間和算力成本。

  • 學習率太大,大概率會跳過最優解,進入無限的訓練和震蕩中。

  • 解決的方法就是,學習率也需要隨著訓練的進行而變化。

過程:

  1. 初始化參數:隨機初始化模型的參數 θ ,如權重 W和偏置 b。

  2. 計算梯度:損失函數 L(θ)對參數 θ 的梯度 ?_θL(θ),表示損失函數在參數空間的變化率。

  3. 更新參數:按照梯度下降公式更新參數:θ := θ - α ?_θ L(θ),其中,α 是學習率,用于控制更新步長。

  4. 迭代更新:重復【計算梯度和更新參數】步驟,直到某個終止條件(如梯度接近0、不再收斂、完成迭代次數等)。

2.2傳統下降方式

根據計算梯度時數據量不同,常見的方式有:

2.2.1批量梯度下降

Batch Gradient Descent BGD

  • 特點

    • 每次更新參數時,使用整個訓練集來計算梯度。

  • 優點

    • 收斂穩定,能準確地沿著損失函數的真實梯度方向下降。

    • 適用于小型數據集。

  • 缺點

    • 對于大型數據集,計算量巨大,更新速度慢。

    • 需要大量內存來存儲整個數據集。

例如,在訓練集中有100個樣本,迭代50輪。

那么在每一輪迭代中,都會一起使用這100個樣本,計算整個訓練集的梯度,并對模型更新。

所以總共會更新50次梯度。

因為每次迭代都會使用整個訓練集計算梯度,所以這種方法可以得到準確的梯度方向。

但如果數據集非常大,那么就導致每次迭代都很慢,計算成本就會很高。

2.2.2隨機梯度下降

Stochastic Gradient Descent, SGD

  • 特點

    • 每次更新參數時,僅使用一個樣本來計算梯度。

  • 優點

    • 更新頻率高,計算快,適合大規模數據集。

    • 能夠跳出局部最小值,有助于找到全局最優解。

  • 缺點

    • 收斂不穩定,容易震蕩,因為每個樣本的梯度可能都不完全代表整體方向。

    • 需要較小的學習率來緩解震蕩。

例如,如果訓練集有100個樣本,迭代50輪,那么每一輪迭代,會遍歷這100個樣本,每次會計算某一個樣本的梯度,然后更新模型參數。

換句話說,100個樣本,迭代50輪,那么就會更新100*50=5000次梯度。

因為每次只用一個樣本訓練,所以迭代速度會非常快。

但更新的方向會不穩定,這也導致隨機梯度下降,可能永遠都不會收斂。

不過也因為這種震蕩屬性,使得隨機梯度下降,可以跳出局部最優解。

這在某些情況下,是非常有用的。

2.2.3小批量梯度下降

Mini-batch Gradient Descent MGBD

  • 特點

    • 每次更新參數時,使用一小部分訓練集(小批量)來計算梯度。

  • 優點

    • 在計算效率和收斂穩定性之間取得平衡。

    • 能夠利用向量化加速計算,適合現代硬件(如GPU)。

  • 缺點

    • 選擇適當的批量大小比較困難;批量太小則接近SGD,批量太大則接近批量梯度下降。

    • 通常會根據硬件算力設置為32\64\128\256等2的次方。

例如,如果訓練集中有100個樣本,迭代50輪。

如果設置小批量的數量是20,那么在每一輪迭代中,會有5次小批量迭代。

換句話說,就是將100個樣本分成5個小批量,每個小批量20個數據,每次迭代用一個小批量。

因此,按照這樣的方式,會對梯度,進行50輪*5個小批量=250次更新。

2.3存在的問題

  • 收斂速度慢:BGD和MBGD使用固定學習率,太大會導致震蕩,太小又收斂緩慢。

  • 局部最小值和鞍點問題:SGD在遇到局部最小值或鞍點時容易停滯,導致模型難以達到全局最優。

  • 訓練不穩定:SGD中的噪聲容易導致訓練過程中不穩定,使得訓練陷入震蕩或不收斂。

2.4優化下降方式

通過對標準的梯度下降進行改進,來提高收斂速度或穩定性。

2.4.1指數加權平均

我們平時說的平均指的是將所有數加起來除以數的個數,很單純的數學。再一個是移動平均數,指的是計算最近鄰的N個數來獲得平均數,感覺比純粹的直接全部求均值高級一點。

指數加權平均:Exponential Moving Average,簡稱EMA,是一種平滑時間序列數據的技術,它通過對過去的值賦予不同的權重來計算平均值。與簡單移動平均不同,EMA賦予最近的數據更高的權重,較遠的數據則權重較低,這樣可以更敏感地反映最新的變化趨勢。

2.4.2 Momentum

動量(Momentum)是對梯度下降的優化方法,可以更好地應對梯度變化和梯度消失問題,從而提高訓練模型的效率和穩定性。它通過引入 指數加權平均 來積累歷史梯度信息,從而在更新參數時形成“動量”,幫助優化算法更快地越過局部最優或鞍點。

特點

  • 慣性效應: 該方法加入前面梯度的累積,這種慣性使得算法沿著當前的方向繼續更新。如遇到鞍點,也不會因梯度逼近零而停滯。

  • 減少震蕩: 該方法平滑了梯度更新,減少在鞍點附近的震蕩,幫助優化過程穩定向前推進。

  • 加速收斂: 該方法在優化過程中持續沿著某個方向前進,能夠更快地穿越鞍點區域,避免在鞍點附近長時間停留。

總結

  • 動量項更新:利用當前梯度和歷史動量來計算新的動量項。

  • 權重參數更新:利用更新后的動量項來調整權重參數。

  • 梯度計算:在每個時間步計算當前的梯度,用于更新動量項和權重參數。

Momentum 算法是對梯度值的平滑調整,但是并沒有對梯度下降中的學習率進行優化。

2.4.3 AdaGrad

AdaGrad(Adaptive Gradient Algorithm)為每個參數引入獨立的學習率,它根據歷史梯度的平方和來調整這些學習率。具體來說,對于頻繁更新的參數,其學習率會逐漸減小;而對于更新頻率較低的參數,學習率會相對較大。AdaGrad避免了統一學習率的不足,更多用于處理稀疏數據和梯度變化較大的問題。

AdaGrad流程:

  1. 初始化
  2. 梯度計算
  3. 累積梯度的平方
  4. 參數更新

優點

  • 自適應學習率:由于每個參數的學習率是基于其梯度的累積平方和 G_{t,i} 來動態調整的,這意味著學習率會隨著時間步的增加而減少,對梯度較大且變化頻繁的方向非常有用,防止了梯度過大導致的震蕩。

  • 適合稀疏數據:AdaGrad 在處理稀疏數據時表現很好,因為它能夠自適應地為那些較少更新的參數保持較大的學習率。

缺點

  1. 學習率過度衰減:隨著時間的推移,累積的時間步梯度平方值越來越大,導致學習率逐漸接近零,模型會停止學習。

  2. 不適合非稀疏數據:在非稀疏數據的情況下,學習率過快衰減可能導致優化過程早期停滯。

AdaGrad是一種有效的自適應學習率算法,然而由于學習率衰減問題,我們會使用改 RMSProp 或 Adam 來替代。

2.4.4 RMSProp

雖然 AdaGrad 能夠自適應地調整學習率,但隨著訓練進行,累積梯度平方 G_t會不斷增大,導致學習率逐漸減小,最終可能變得過小,導致訓練停滯。

RMSProp(Root Mean Square Propagation)是一種自適應學習率的優化算法,在時間步中,不是簡單地累積所有梯度平方和,而是使用指數加權平均來逐步衰減過時的梯度信息。旨在解決 AdaGrad 學習率單調遞減的問題。它通過引入 指數加權平均 來累積歷史梯度的平方,從而動態調整學習率。

優點

  • 適應性強:RMSProp自適應調整每個參數的學習率,對于梯度變化較大的情況非常有效,使得優化過程更加平穩。

  • 適合非稀疏數據:相比于AdaGrad,RMSProp更加適合處理非稀疏數據,因為它不會讓學習率減小到幾乎為零。

  • 解決過度衰減問題:通過引入指數加權平均,RMSProp避免了AdaGrad中學習率過快衰減的問題,保持了學習率的穩定性

缺點

依賴于超參數的選擇:RMSProp的效果對衰減率 \gamma 和學習率 \eta 的選擇比較敏感,需要一些調參工作。

2.4.5 Adam

Adam(Adaptive Moment Estimation)算法將動量法和RMSProp的優點結合在一起:

  • 動量法:通過一階動量(即梯度的指數加權平均)來加速收斂,尤其是在有噪聲或梯度稀疏的情況下。

  • RMSProp:通過二階動量(即梯度平方的指數加權平均)來調整學習率,使得每個參數的學習率適應其梯度的變化。

Adam過程

  1. 初始化

  2. 梯度計算

  3. 一階動量估計(梯度的指數加權平均)

  4. 二階動量估計(梯度平方的指數加權平均)

  5. 偏差校正

優點

  1. 高效穩健:Adam結合了動量法和RMSProp的優勢,在處理非靜態、稀疏梯度和噪聲數據時表現出色,能夠快速穩定地收斂。

  2. 自適應學習率:Adam通過一階和二階動量的估計,自適應調整每個參數的學習率,避免了全局學習率設定不合適的問題。

  3. 適用大多數問題:Adam幾乎可以在不調整超參數的情況下應用于各種深度學習模型,表現良好。

缺點

  1. 超參數敏感:盡管Adam通常能很好地工作,但它對初始超參數(如β1、β2 和 η)仍然較為敏感,有時需要仔細調參。

  2. 過擬合風險:由于Adam會在初始階段快速收斂,可能導致模型陷入局部最優甚至過擬合。因此,有時會結合其他優化算法(如SGD)使用。

2.5總結

梯度下降算法通過不斷更新參數來最小化損失函數,是反向傳播算法中計算權重調整的基礎。在實際應用中,根據數據的規模和計算資源的情況,選擇合適的梯度下降方式(批量、隨機、小批量)及其變種(如動量法、Adam等)可以顯著提高模型訓練的效率和效果。

Adam是目前最為流行的優化算法之一,因其穩定性和高效性,廣泛應用于各種深度學習模型的訓練中。Adam結合了動量法和RMSProp的優點,能夠在不同情況下自適應調整學習率,并提供快速且穩定的收斂表現。

import torch
from sympy.abc import alpha
from torch.utils.data import TensorDataset,DataLoader
from torch import nn,optimdef test01():model = nn.Linear(10,5)x = torch.randn(10000,10)y = torch.randn(10000,5)criterion = nn.MSELoss()# momentum:動量,根據歷史梯度增加慣性# 參數值:動量系數,一般取0.9opt = optim.SGD(model.parameters(),lr=0.01,momentum=0.9)dataset = TensorDataset(x,y)# 批量梯度下降# dataloader = DataLoader(#     dataset=dataset,#     batch_size=len( dataset),#     shuffle= True# )# 隨機梯度下降,隨機選擇一條樣本進行梯度更新# dataloader = DataLoader(#     dataset=dataset,#     batch_size=1,#     shuffle= True# )# 小批量梯度下降dataloader = DataLoader(dataset=dataset,batch_size=64,shuffle= True)epochs = 200for epoch in range(epochs):for tx,ty in dataloader:y_pred = model(tx)loss = criterion(y_pred,ty)opt.zero_grad()loss.backward()opt.step()print(f'epoch:{epoch},loss:{loss.item()}')def test02():model = nn.Linear(10,5)x = torch.randn(1000,10)y = torch.randn(1000,5)criterion = nn.MSELoss()# Adagrad:自適應學習率優化器# 原理:歷史梯度平方和作為學習率的分母,動態調整學習率# 優點:自適應動態調整學習率# 缺點:隨著訓練時間增加,歷史梯度平方和越來越大,導致學習率越來越小,可能會停止參數更新# eps:避免學習率的分母為0,是一個非常小的數字# opt = optim.Adagrad(model.parameters(),lr=0.1,eps=1e-08)# RMSProp:自適應學習率優化器# 原理:使用指數加權平均對歷史梯度平方求和,將平方和作為分母調整學習率# 優點:緩解歷史梯度平方和快速變大,使學習率衰減更加平穩# 缺點:需要調整alpha參數,找到最優值# opt = optim.RMSprop(model.parameters(),lr=0.1,alpha=0.9,eps=1e-08)# Adam:自適應優化器# 結合了動量和RMSprop,既優化了梯度,又能動態調整學習率# 缺點是對參數設置比較敏感,需要根據實際情況進行調整# betas參數:是一個元組,第一個元素是一階動量的系數0.9,第二個元素是二階動量的系數0.999,兩個系數是經驗值opt = optim.Adam(model.parameters(),lr=0.1,betas=(0.9,0.999),eps=1e-08)for epoch in range(50):y_pred = model(x)loss = criterion(y_pred,y)opt.zero_grad()loss.backward()opt.step()print(f'loss:{loss.item()}')if __name__ == '__main__':# test01()test02()

七、過擬合和欠擬合

在訓練深層神經網絡時,由于模型參數較多,在數據量不足時很容易過擬合。而正則化技術主要就是用于防止過擬合,提升模型的泛化能力(對新數據表現良好)和魯棒性(對異常數據表現良好)。

1、概念

1.1過擬合

過擬合是指模型對訓練數據擬合能力很強并表現很好,但在測試數據上表現較差。

過擬合常見原因有:

  1. 數據量不足:當訓練數據較少時,模型可能會過度學習數據中的噪聲和細節。

  2. 模型太復雜:如果模型很復雜,也會過度學習訓練數據中的細節和噪聲。

  3. 正則化強度不足:如果正則化強度不足,可能會導致模型過度學習訓練數據中的細節和噪聲。

1.2欠擬合

欠擬合是由于模型學習能力不足,無法充分捕捉數據中的復雜關系。

1.3如何判斷

那如何判斷一個錯誤的結果是過擬合還是欠擬合呢?

過擬合

訓練誤差低,但驗證時誤差高。模型在訓練數據上表現很好,但在驗證數據上表現不佳,說明模型可能過度擬合了訓練數據中的噪聲或特定模式。

欠擬合

訓練誤差和測試誤差都高。模型在訓練數據和測試數據上的表現都不好,說明模型可能太簡單,無法捕捉到數據中的復雜模式。

2、解決欠擬合

欠擬合的解決思路比較直接:

  1. 增加模型復雜度:引入更多的參數、增加神經網絡的層數或節點數量,使模型能夠捕捉到數據中的復雜模式。

  2. 增加特征:通過特征工程添加更多有意義的特征,使模型能夠更好地理解數據。

  3. 減少正則化強度:適當減小 L1、L2 正則化強度,允許模型有更多自由度來擬合數據。

  4. 訓練更長時間:如果是因為訓練不足導致的欠擬合,可以增加訓練的輪數或時間.

3、解決過擬合

避免模型參數過大是防止過擬合的關鍵步驟之一。

模型的復雜度主要由權重w決定,而不是偏置b。偏置只是對模型輸出的平移,不會導致模型過度擬合數據。

怎么控制權重w,使w在比較小的范圍內?

考慮損失函數,損失函數的目的是使預測值與真實值無限接近,如果在原來的損失函數上添加一個非0的變量

其中f(w)是關于權重w的函數,f(w)>0

要使L1變小,就要使L變小的同時,也要使f(w)變小。從而控制權重w在較小的范圍內。

3.1 L2正則化

數學表達

其中:

  • L(θ) 是原始損失函數(比如均方誤差、交叉熵等)。

  • \lambda 是正則化強度,控制正則化的力度。

  • θi 是模型的第 i 個權重參數。

  • 1/2Σ_{i} θi^2 是所有權重參數的平方和,稱為 L2 正則化項。

梯度更新

在 L2 正則化下,梯度更新時,不僅要考慮原始損失函數的梯度,還要考慮正則化項的影響。更新規則為:

作用

  1. 防止過擬合:當模型過于復雜、參數較多時,模型會傾向于記住訓練數據中的噪聲,導致過擬合。L2 正則化通過抑制參數的過大值,使得模型更加平滑,降低模型對訓練數據噪聲的敏感性。

  2. 限制模型復雜度:L2 正則化項強制權重參數盡量接近 0,避免模型中某些參數過大,從而限制模型的復雜度。通過引入平方和項,L2 正則化鼓勵模型的權重均勻分布,避免單個權重的值過大。

  3. 提高模型的泛化能力:正則化項的存在使得模型在測試集上的表現更加穩健,避免在訓練集上取得極高精度但在測試集上表現不佳。

  4. 平滑權重分布:L2 正則化不會將權重直接變為 0,而是將權重值縮小。這樣模型就更加平滑的擬合數據,同時保留足夠的表達能力。

3.2 L1正則化

數學表達

梯度更新

作用

  1. 稀疏性:L1 正則化的一個顯著特性是它會促使許多權重參數變為 。這是因為 L1 正則化傾向于將權重絕對值縮小到零,使得模型只保留對結果最重要的特征,而將其他不相關的特征權重設為零,從而實現 特征選擇 的功能。

  2. 防止過擬合:通過限制權重的絕對值,L1 正則化減少了模型的復雜度,使其不容易過擬合訓練數據。相比于 L2 正則化,L1 正則化更傾向于將某些權重完全移除,而不是減小它們的值。

  3. 簡化模型:由于 L1 正則化會將一些權重變為零,因此模型最終會變得更加簡單,僅依賴于少數重要特征。這對于高維度數據特別有用,尤其是在特征數量遠多于樣本數量的情況下。

  4. 特征選擇:因為 L1 正則化會將部分權重置零,因此它天然具有特征選擇的能力,有助于自動篩選出對模型預測最重要的特征。

L1與L2對比

  • L1 正則化 更適合用于產生稀疏模型,會讓部分權重完全為零,適合做特征選擇。

  • L2 正則化 更適合平滑模型的參數,避免過大參數,但不會使權重變為零,適合處理高維特征較為密集的場景。

3.3 Dropout

Dropout 的工作流程如下:

  1. 在每次訓練迭代中,隨機選擇一部分神經元(通常以概率 p丟棄,比如 p=0.5)。

  2. 被選中的神經元在當前迭代中不參與前向傳播和反向傳播。

  3. 在測試階段,所有神經元都參與計算,但需要對權重進行縮放(通常乘以 1?p),以保持輸出的期望值一致。

Dropout 是一種在訓練過程中隨機丟棄部分神經元的技術。它通過減少神經元之間的依賴來防止模型過于復雜,從而避免過擬合。

import torch
from torch import nn
from torch.onnx.symbolic_opset9 import dropoutdef test01():x = torch.randint(0,10,(5,6),dtype=torch.float)dropout = nn.Dropout(p=0.5)print(x)print(dropout(x))if __name__ == '__main__':test01()

3.4數據增強

樣本數量不足(即訓練數據過少)是導致過擬合(Overfitting)的常見原因之一,可以從以下角度理解:

  • 當訓練數據過少時,模型容易“記住”有限的樣本(包括噪聲和無關細節),而非學習通用的規律。

  • 簡單模型更可能捕捉真實規律,但數據不足時,復雜模型會傾向于擬合訓練集中的偶然性模式(噪聲)。

  • 樣本不足時,訓練集的分布可能與真實分布偏差較大,導致模型學到錯誤的規律。

  • 小數據集中,個別樣本的噪聲(如標注錯誤、異常值)會被放大,模型可能將噪聲誤認為規律。

數據增強(Data Augmentation)是一種通過人工生成或修改訓練數據來增加數據集多樣性的技術,常用于解決過擬合問題。數據增強通過“模擬”更多訓練數據,迫使模型學習泛化性更強的規律,而非訓練集中的偶然性模式。其本質是一種低成本的正則化手段,尤其在數據稀缺時效果顯著。

在了解計算機如何處理圖像之前,需要先了解圖像的構成元素。

圖像是由像素點組成的,每個像素點的值范圍為: [0, 255], 像素值越大意味著較亮。比如一張 200x200 的圖像, 則是由 40000 個像素點組成, 如果每個像素點都是 0 的話, 意味著這是一張全黑的圖像。

我們看到的彩色圖一般都是多通道的圖像, 所謂多通道可以理解為圖像由多個不同的圖像層疊加而成, 例如我們看到的彩色圖像一般都是由 RGB 三個通道組成的,還有一些圖像具有 RGBA 四個通道,最后一個通道為透明通道,該值越小,則圖像越透明。

數據增強是提高模型泛化能力(魯棒性)的一種有效方法,尤其在圖像分類、目標檢測等任務中。數據增強可以模擬更多的訓練樣本,從而減少過擬合風險。數據增強通過torchvision.transforms模塊來實現。

數據增強的好處

大幅度降低數據采集和標注成本;

模型過擬合風險降低,提高模型泛化能力;

官方地址:

transforms:Transforming and augmenting images — Torchvision 0.22 documentation

transforms:

常用變換類

  • transforms.Compose:將多個變換操作組合成一個流水線。

  • transforms.ToTensor:將 PIL 圖像或 NumPy 數組轉換為 PyTorch 張量,將圖像數據從 uint8 類型 (0-255) 轉換為 float32 類型 (0.0-1.0)。

  • transforms.Normalize:對張量進行標準化。

  • transforms.Resize:調整圖像大小。

  • transforms.CenterCrop:從圖像中心裁剪指定大小的區域。

  • transforms.RandomCrop:隨機裁剪圖像。

  • transforms.RandomHorizontalFlip:隨機水平翻轉圖像。

  • transforms.RandomVerticalFlip:隨機垂直翻轉圖像。

  • transforms.RandomRotation:隨機旋轉圖像。

  • transforms.ColorJitter:隨機調整圖像的亮度、對比度、飽和度和色調。

  • transforms.RandomGrayscale:隨機將圖像轉換為灰度圖像。

  • transforms.RandomResizedCrop:隨機裁剪圖像并調整大小。

3.4.1圖片縮放
def test01():path = 'datasets/images/100.jpg'img = Image.open(path)print( img.size)transform = transforms.Compose([transforms.Resize((224,224)),transforms.ToTensor()])t_img = transform(img)print(t_img.shape)t_img = torch.permute(t_img, (1,2,0))plt.imshow(t_img)plt.show()
3.4.2隨機裁剪
def test02():path = 'datasets/images/100.jpg'img = Image.open(path)print(img.size)transform = transforms.Compose([# 隨機裁剪transforms.RandomCrop(size=(224,224)),transforms.ToTensor()])t_img = transform(img)print(t_img.shape)t_img = torch.permute(t_img, (1, 2, 0))plt.imshow(t_img)plt.show()
3.4.3隨機水平翻轉

RandomHorizontalFlip(p):隨機水平翻轉圖像,參數p表示翻轉概率(0 ≤ p ≤ 1),p=1 表示必定翻轉,p=0 表示不翻轉

def test03():path = 'datasets/images/100.jpg'img = Image.open(path)print(img.size)transform = transforms.Compose([# 隨機水平翻轉transforms.RandomHorizontalFlip(p=0.5),transforms.ToTensor()])t_img = transform(img)print(t_img.shape)t_img = torch.permute(t_img, (1, 2, 0))plt.imshow(t_img)plt.show()
3.4.4調整圖片顏色

transforms.ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)

brightness:

  • 亮度調整的范圍。

  • 可以float(min, max) 元組:

    • 如果是 float(如 brightness=0.2),則亮度在 [max(0, 1 - 0.2), 1 + 0.2] = [0.8, 1.2] 范圍內隨機縮放。

    • 如果是 (min, max)(如 brightness=(0.5, 1.5)),則亮度在 [0.5, 1.5] 范圍內隨機縮放。

contrast:

  • 對比度調整的范圍。

  • 格式與 brightness 相同。

saturation:

  • 飽和度調整的范圍。

  • 格式與 brightness 相同。

hue:

  • 色調調整的范圍。

  • 可以是一個浮點數(表示相對范圍)或一個元組 (min, max)。

  • 取值范圍必須為 [-0.5, 0.5](因為色相在 HSV 色彩空間中是循環的,超出范圍會導致顏色異常)。

3.4.5隨機旋轉

RandomRotation用于對圖像進行隨機旋轉。

transforms.RandomRotation(
? ? degrees,?
? ? interpolation=InterpolationMode.NEAREST,?
? ? expand=False,?
? ? center=None,?
? ? fill=0
)

degrees:

  • 旋轉角度的范圍,可以是一個浮點數或元組 (min_degree, max_degree)。

  • 例如,degrees=30 表示旋轉角度在 [-30, 30] 之間隨機選擇。

  • 例如,degrees=(30, 60) 表示旋轉角度在 [30, 60] 之間隨機選擇。

interpolation:

  • 插值方法,用于旋轉圖像。

  • 默認是 InterpolationMode.NEAREST(最近鄰插值)。

  • 其他選項包括 InterpolationMode.BILINEAR(雙線性插值)、InterpolationMode.BICUBIC(雙三次插值)等。

expand:

  • 是否擴展圖像大小以適應旋轉后的圖像。如:當需要保留完整旋轉后的圖像時(如醫學影像、文檔掃描)

  • 如果為 True,旋轉后的圖像可能會比原始圖像大。

  • 如果為 False,旋轉后的圖像大小與原始圖像相同。

center:

  • 旋轉中心點的坐標,默認為圖像中心。

  • 可以是一個元組 (x, y),表示旋轉中心的坐標。

fill:

  • 旋轉后圖像邊緣的填充值。

  • 可以是一個浮點數(用于灰度圖像)或一個元組(用于 RGB 圖像)。默認填充0(黑色)

def test04():path = 'datasets/images/100.jpg'img = Image.open(path)print(img.size)transform = transforms.Compose([# 隨機旋轉# degress參數:degress=30,表示在(-30,30)范圍內隨機旋轉,degree=(30,60),表示在該范圍內隨機旋轉transforms.RandomRotation(degrees=45),transforms.ToTensor()])t_img = transform(img)print(t_img.shape)t_img = torch.permute(t_img, (1, 2, 0))plt.imshow(t_img)plt.show()
3.4.6圖片轉Tensor
import torch
from PIL import Image
from torchvision import transforms
import osdef test001():dir_path = os.path.dirname(__file__)file_path = os.path.join(dir_path,'img', '1.jpg')file_path = os.path.relpath(file_path)print(file_path)# 1. 讀取圖片img = Image.open(file_path)# transforms.ToTensor()用于將 PIL 圖像或 NumPy 數組轉換為 PyTorch 張量,并自動進行數值歸一化和維度調整# 將像素值從 [0, 255] 縮放到 [0.0, 1.0](浮點數)# 自動將圖像格式從 (H, W, C)(高度、寬度、通道)轉換為 PyTorch 標準的 (C, H, W)transform = transforms.ToTensor()img_tensor = transform(img)print(img_tensor)if __name__ == "__main__":test001()
3.4.7 Tensor轉圖片
def test05():t = torch.randn(3, 224, 224)transform = transforms.Compose([# 張量轉PIL圖片transforms.ToPILImage()])img = transform(t)print(img.size)img.show()
3.4.8歸一化
  • 標準化:將圖像的像素值從原始范圍(如 [0, 255] 或 [0, 1])轉換為均值為 0、標準差為 1 的分布。

  • 加速訓練:標準化后的數據分布更均勻,有助于加速模型訓練。

  • 提高模型性能:標準化可以使模型更容易學習到數據的特征,提高模型的收斂性和穩定性。

mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])]

均值(Mean):數據集中所有圖像在每個通道上的像素值的平均值。

標準差(Std):數據集中所有圖像在每個通道上的像素值的標準差。

RGB 三個通道的均值和標準差 不是隨便定義的,而是需要根據具體的數據集進行統計計算。這些值是 ImageNet 數據集的統計結果,已成為計算機視覺任務的默認標準。

def test06():path = 'datasets/images/100.jpg'img = Image.open(path)print(img.size)transform = transforms.Compose([transforms.ToTensor(),# Normalize:標準化# mean:均值# std:標準差# 如果數據集是官方數據集,需要查看官方提供的mean和std值# 如果是自定義的數據集,可以將mean和std設置為[0.5, 0.5, 0.5],是一個經驗值# Normalize要在ToTensor()之后執行,否則會報錯transforms.Normalize(mean=[0.5, 0.5, 0.5], std=[0.5, 0.5, 0.5])])t_img = transform(img)print(t_img.shape)t_img = torch.permute(t_img, (1, 2, 0))plt.imshow(t_img)plt.show()
3.4.9數據增強整合

使用transforms.Compose()把要增強的操作整合到一起:

from PIL import Image
from pathlib import Path
import matplotlib.pyplot as plt
import numpy as np
import torch
from torchvision import transforms, datasets, utilsdef test01():# 定義數據增強和歸一化transform = transforms.Compose([transforms.RandomHorizontalFlip(),  # 隨機水平翻轉transforms.RandomRotation(10),  # 隨機旋轉 ±10 度transforms.RandomResizedCrop(32, scale=(0.8, 1.0)),  # 隨機裁剪到 32x32,縮放比例在0.8到1.0之間transforms.ColorJitter(brightness=0.2, contrast=0.2, saturation=0.2, hue=0.1),  # 隨機調整亮度、對比度、飽和度、色調transforms.ToTensor(),  # 轉換為 Tensortransforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5)),  # 歸一化,這是一種常見的經驗設置,適用于數據范圍 [0, 1],使其映射到 [-1, 1]])# 加載 CIFAR-10 數據集,并應用數據增強trainset = datasets.CIFAR10(root="./cifar10_data", train=True, download=True, transform=transform)dataloader = DataLoader(trainset, batch_size=4, shuffle=False)# 獲取一個批次的數據images, labels = next(iter(dataloader))# 還原圖片并顯示plt.figure(figsize=(10, 5))for i in range(4):# 反歸一化:將像素值從 [-1, 1] 還原到 [0, 1]img = images[i] / 2 + 0.5# 轉換為 PIL 圖像img_pil = transforms.ToPILImage()(img)# 顯示圖片plt.subplot(1, 4, i + 1)plt.imshow(img_pil)plt.axis('off')plt.title(f'Label: {labels[i]}')plt.show()if __name__ == "__main__":test01()

八、批量標準化

1、訓練階段的批量標準化

  1. 計算均值和方差
  2. 標準化
  3. 縮放和平移
  4. 更新全局統計量

2、測試階段的批量標準化

在測試階段,由于沒有 mini-batch 數據,無法直接計算當前 batch 的均值和方差。因此,使用訓練階段通過 EMA 計算的全局統計量(均值和方差)來進行標準化。

在測試階段,使用全局統計量對輸入數據進行標準化:

然后對標準化后的數據進行縮放和平移:

為什么使用全局統計量?

一致性

  • 在測試階段,輸入數據通常是單個樣本或少量樣本,無法準確計算均值和方差。

  • 使用全局統計量可以確保測試階段的行為與訓練階段一致。

穩定性

  • 全局統計量是通過訓練階段的大量 mini-batch 數據計算得到的,能夠更好地反映數據的整體分布。

  • 使用全局統計量可以減少測試階段的隨機性,使模型的輸出更加穩定。

效率

  • 在測試階段,使用預先計算的全局統計量可以避免重復計算,提高效率。

3、作用

批量標準化(Batch Normalization, BN)通過以下幾個方面來提高神經網絡的訓練穩定性、加速訓練過程并減少過擬合:

3.1 緩解梯度問題

標準化處理可以防止激活值過大或過小,避免了激活函數(如 Sigmoid 或 Tanh)飽和的問題,從而緩解梯度消失或爆炸的問題。

3.2 加速訓練

由于 BN 使得每層的輸入數據分布更為穩定,因此模型可以使用更高的學習率進行訓練。這可以加快收斂速度,并減少訓練所需的時間。

3.3 減少過擬合

  • 類似于正則化:雖然 BN 不是一種傳統的正則化方法,但它通過對每個批次的數據進行標準化,可以起到一定的正則化作用。它通過在訓練過程中引入了噪聲(由于批量均值和方差的估計不完全準確),這有助于提高模型的泛化能力。

  • 避免對單一數據點的過度擬合:BN 強制模型在每個批次上進行標準化處理,減少了模型對單個訓練樣本的依賴。這有助于模型更好地學習到數據的整體特征,而不是對特定樣本的噪聲進行過度擬合。

4、函數

torch.nn.BatchNorm1d 是 PyTorch 中用于一維數據的批量標準化(Batch Normalization)模塊。

torch.nn.BatchNorm1d(
? ? num_features, ? ? ? ? # 輸入數據的特征維度
? ? eps=1e-05, ? ? ? ? ? # 用于數值穩定性的小常數
? ? momentum=0.1, ? ? ? ?# 用于計算全局統計量的動量
? ? affine=True, ? ? ? ? # 是否啟用可學習的縮放和平移參數
? ? track_running_stats=True, ?# 是否跟蹤全局統計量
? ? device=None, ? ? ? ? # 設備類型(如 CPU 或 GPU)
? ? dtype=None ? ? ? ? ? # 數據類型
)

參數說明:

eps:用于數值穩定性的小常數,添加到方差的分母中,防止除零錯誤。默認值:1e-05

momentum:用于計算全局統計量(均值和方差)的動量。默認值:0.1,參考本節1.4

affine:是否啟用可學習的縮放和平移參數(γ和 β)。如果 affine=True,則模塊會學習兩個參數;如果 affine=False,則不學習參數,直接輸出標準化后的值 \hat x_i。默認值:True

track_running_stats:是否跟蹤全局統計量(均值和方差)。如果 track_running_stats=True,則在訓練過程中計算并更新全局統計量,并在測試階段使用這些統計量。如果 track_running_stats=False,則不跟蹤全局統計量,每次標準化都使用當前 mini-batch 的統計量。默認值:True

import torch
from torch import nn,optim
from sklearn.datasets import make_circles
from sklearn.model_selection import train_test_split
from matplotlib import pyplot as pltdef build_data():x , y =  make_circles(n_samples=2000,factor=0.4,noise=0.1,random_state=42)print(x[0])print(y[0:5])x = torch.tensor(x,dtype=torch.float)y = torch.tensor(y,dtype=torch.long)# plt.scatter(x[:,0],x[:,1],c=y)# plt.show()x_train,x_test,y_train,y_test = train_test_split(x,y,test_size=0.3,random_state=42)return x_train,x_test,y_train,y_test# 構建網絡模型,帶批量標準化
class NetWithBN(nn.Module):def __init__(self,in_features,out_features):super().__init__()self.fc1 = nn.Linear(in_features,128)self.bn1 = nn.BatchNorm1d(128)self.relu1  = nn.ReLU()self.fc2 = nn.Linear(128,64)self.bn2 = nn.BatchNorm1d(64)self.relu2 = nn.ReLU()self.fn3 = nn.Linear(64,out_features)def forward(self,x):x = self.relu1(self.bn1(self.fc1(x)))x = self.relu2(self.bn2(self.fc2(x)))x = self.fn3(x)return x# 創建網絡模型,不使用批量標準化
class NetWithoutBN(nn.Module):def __init__(self,in_features,out_features):super().__init__()self.fc1 = nn.Linear(in_features,128)self.relu1  = nn.ReLU()self.fc2 = nn.Linear(128,64)self.relu2 = nn.ReLU()self.fn3 = nn.Linear(64,out_features)def forward(self,x):x = self.relu1(self.fc1(x))x = self.relu2(self.fc2(x))x = self.fn3(x)return xdef train(model,x_train,y_train,epochs):# 如果網絡模型中使用了dropout或批量標準化,train()默認啟動dropout或批量標準化的功能model.train()criterion = nn.CrossEntropyLoss()opt = optim.SGD(model.parameters(),lr=0.1)loss_list = []for epoch in range(epochs):y_pred = model(x_train)print(y_pred[0])print(y_train.shape)loss = criterion(y_pred,y_train)opt.zero_grad()loss.backward()opt.step()loss_list.append(loss.item())return loss_listdef eval(model,x_test,y_test,epochs):# 驗證階段會自動關閉dropout或批量標準化的參數更新model.eval()acc_list = []for epoch in range(epochs):with torch.no_grad():y_gred = model(x_test)_, pred = torch.max(y_gred,dim=1)correct = (pred == y_test).sum().item()acc = correct / len(y_test)acc_list.append((acc))return acc_listdef plot(bn_loss_list,no_bn_loss_list,bn_acc_list,no_bn_acc_list):fig = plt.figure(figsize=(12, 5))ax1 = fig.add_subplot(1, 2, 1)ax1.plot(bn_loss_list, 'b', label='BN')ax1.plot(no_bn_loss_list, 'r', label='NoBN')ax1.legend()ax2 = fig.add_subplot(1, 2, 2)ax2.plot(bn_acc_list, 'b', label='BN')ax2.plot(no_bn_acc_list, 'r', label='NoBN')ax2.legend()plt.show()if __name__ == '__main__':x_train,x_test,y_train,y_test =build_data()bn_model = NetWithBN(2,2)nobn_model = NetWithoutBN(2,2)bn_loss_list = train(bn_model,x_train,y_train,100)no_bn_loss_list = train(nobn_model,x_train,y_train,100)bn_acc_list = eval(bn_model,x_test,y_test,100)no_bn_acc_list = eval(nobn_model,x_test,y_test,100)plot(bn_loss_list,no_bn_loss_list,bn_acc_list,no_bn_acc_list)

九、模型的保存和加載

訓練一個模型通常需要大量的數據、時間和計算資源。通過保存訓練好的模型,可以滿足后續的模型部署、模型更新、遷移學習、訓練恢復等各種業務需要求。

1、標準網絡模型構建

class MyModle(nn.Module):def __init__(self, input_size, output_size):super(MyModle, self).__init__()# 創建一個全連接網絡(full connected layer)self.fc1 = nn.Linear(input_size, 128)self.fc2 = nn.Linear(128, 64)self.fc3 = nn.Linear(64, output_size)def forward(self, x):x = self.fc1(x)x = self.fc2(x)output = self.fc3(x)return output# 創建模型實例
model = MyModel(input_size=10, output_size=2)
# 輸入數據
x = torch.randn(5, 10)
# 調用模型
output = model(x)

forward 方法是 PyTorch 中 nn.Module 類的必須實現的方法。它是定義神經網絡前向傳播邏輯的地方,決定了數據如何通過網絡層傳遞并生成輸出。同時forward 方法定義了計算圖,PyTorch 會根據這個計算圖自動計算梯度并更新參數。

2、序列化模型對象

模型序列化對象的保存和加載:

模型保存

torch.save(obj, f, pickle_module=pickle, pickle_protocol=DEFAULT_PROTOCOL, _use_new_zipfile_serialization=True)

參數說明:

  • obj:要保存的對象,可以是模型、張量、字典等。

  • f:保存文件的路徑或文件對象。可以是字符串(文件路徑)或文件描述符。

  • pickle_module:用于序列化的模塊,默認是 Python 的 pickle 模塊。

  • pickle_protocol:pickle 模塊的協議版本,默認是 DEFAULT_PROTOCOL(通常是最高版本)。

模型加載

torch.load(f, map_location=None, pickle_module=pickle, **pickle_load_args)

參數說明:

  • f:文件路徑或文件對象。可以是字符串(文件路徑)或文件描述符。

  • map_location:指定加載對象的設備位置(如 CPU 或 GPU)。默認是 None,表示保持原始設備位置。例如:map_location=torch.device('cpu') 將對象加載到 CPU。

  • pickle_module:用于反序列化的模塊,默認是 Python 的 pickle 模塊。

  • pickle_load_args:傳遞給 pickle_module.load() 的額外參數。

3、保存模型參數

這種形式更常用,只需要保存權重、偏置、準確率等相關參數,都可以在加載后打印觀察!

import torch
from torch import nnclass MyNet(nn.Module):def __init__(self):super().__init__()self.fc1 = nn.Linear(10,64)self.fc2 = nn.Linear(64,5)def forward(self,x):x = self.fc1(x)x = self.fc2(x)return x# 保存模型
def test01():model = MyNet()print( model)torch.save(model,'./model/fcnn_model.pt')# 加載模型
# 完整的模型
def test02():model = torch.load('./model/fcnn_model.pt')print( model)# 保存模型參數
def test03():model = MyNet()state_dict = model.state_dict()torch.save(state_dict,'./model/fcnn_state.pt')# 加載模型參數
# 如果保存的是模型參數,加載的是字典,內容是模型參數,并不是完整的模型
# 需要事先初始化模型,然后把模型參數導入到模型中
def test04():model = MyNet()state_dict = torch.load('./model/fcnn_state.pt')model.load_state_dict(state_dict)if __name__ == '__main__':# test01()test02()

十、項目實戰

1.使用全連接網絡訓練和驗證MNIST數據集

# 使用全連接網絡訓練和預測MINIST數據集
# 1.數據準備:通過數據加載器加載官方MINIST數據集
# 2.構建網絡結構
# 3.實現訓練方法:使用交叉熵損失函數、Adam優化器
# 4.實現驗證方法
# 5.通過測試圖片進行預測import torch
from torch import nn,optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoader
from PIL import Imagedef build_data():transform = transforms.Compose([transforms.Resize((28, 28)),  # 正確寫法:調整為28x28transforms.ToTensor(),])# 訓練數據集train_dataset = datasets.MNIST(root = './datasets',train = True,download=True,transform=transform,)# 驗證數據集eval_dataset = datasets.MNIST(root = './datasets',train = False,download=True,transform=transform,)# 訓練數據加載器train_dataloader = DataLoader(dataset=train_dataset,batch_size=64,shuffle=True,)# 驗證數據加載器eval_dataloader = DataLoader(dataset=eval_dataset,batch_size=64,shuffle=True,)return train_dataloader,eval_dataloader# 構建網絡架構
class MNISTNet(nn.Module):def __init__(self,in_fearures,out_featuers):super().__init__()self.fc1 = nn.Linear(in_fearures,128)self.bn1 = nn.BatchNorm1d(128)self.relu1 = nn.ReLU()self.fc2 = nn.Linear(128,64)self.bn2 = nn.BatchNorm1d(64)self.relu2 = nn.ReLU()self.fn3 = nn.Linear(64,out_featuers)def forward(self,x):x = x.view(-1,1*28*28)x = self.relu1(self.bn1(self.fc1(x)))x = self.relu2(self.bn2(self.fc2(x)))x = self.fn3(x)return xdef train(model,train_dataloader,lr,epochs):model.train()criterion = nn.CrossEntropyLoss()opt = optim.Adam(model.parameters(),lr=lr,betas=(0.9,0.999),eps=1e-08,weight_decay=0.001)for epoch in range(epochs):correct = 0for tx,ty in train_dataloader:y_pred = model(tx)loss = criterion(y_pred,ty)opt.zero_grad()loss.backward()opt.step()_,pred = torch.max(y_pred.data,dim=1)correct += (pred==ty).sum().item()acc = correct / len(train_dataloader.dataset)print(f'epoch:{epoch},loss:{loss.item():.4f},acc:{acc:.4f}')def eval(model,eval_dataloader):model.eval()criterion = nn.CrossEntropyLoss()correct = 0for vx,vy in eval_dataloader:with torch.no_grad():y_pred = model(vx)loss = criterion(y_pred,vy)_,pred = torch.max(y_pred.data,dim=1)correct += (pred==vy).sum().item()acc = correct / len(eval_dataloader.dataset)print(f'loss:{loss.item()},acc:{acc}')def save_model(model,path):torch.save(model.state_dict(),path)def load_model(path):model = MNISTNet(1 * 28 * 28,10)model.load_state_dict(torch.load(path))return modeldef predict(test_path,model_path):transform = transforms.Compose([transforms.Resize((28,28)),transforms.ToTensor(),])img = Image.open(test_path).convert('L')t_img = transform(img).unsqueeze(0)model = load_model(model_path)model.eval()with torch.no_grad():y_pred = model(t_img)_,pred = torch.max(y_pred.data,dim=1)print(f'預測分類:{pred.item()}')if __name__ == '__main__':# train_dataloader,val_dataloader = build_data()# model = MNISTNet(1 * 28 * 28,10)# train(model,train_dataloader,lr=0.01,epochs=20)# eval(model,val_dataloader)# save_model(model,'./model/mnist_model.pt')predict('./datasets/images/8.png', './model/mnist_model.pt')

2.使用全連接網絡訓練和驗證CIFAR10數據集

import torch
from torch import nn,optim
from torchvision import datasets,transforms
from torch.utils.data import DataLoaderdef build_data():# 數據轉換transform = transforms.Compose([transforms.ToTensor(),transforms.Normalize((0.4914, 0.4822, 0.4465),  (0.2023, 0.1994, 0.2010))])# 數據準備# 訓練數據集train_dataset = datasets.CIFAR10(root='./datasets',train=True,transform=transform,download=True)# 驗證數據集eval_dataset = datasets.CIFAR10(root='./datasets',train=False,transform=transform,download=True)# 訓練集數據加載器train_loader = DataLoader(dataset=train_dataset,batch_size=128,shuffle=True)# 驗證集數據加載器eval_loader = DataLoader(dataset=eval_dataset,batch_size=256,shuffle=False)return train_loader,eval_loader# 定義網絡結構
class CIFAR10Net(nn.Module):def __init__(self,in_features,out_features):super().__init__()self.fc1 = nn.Linear(in_features,2048)self.bn1 = nn.BatchNorm1d(2048)self.dropout1 = nn.Dropout(0.3)self.fc2 = nn.Linear(2048,1024)self.bn2 = nn.BatchNorm1d(1024)self.dropout2 = nn.Dropout(0.3)self.fc3 = nn.Linear(1024,512)self.bn3 = nn.BatchNorm1d(512)self.fc4 = nn.Linear(512,256)self.bn4 = nn.BatchNorm1d(256)self.fc5 = nn.Linear(256,out_features)self.relu = nn.ReLU()def forward(self,x):x = x.view(-1,32*32*3)x = self.dropout1(self.bn1(self.fc1(x)))x = self.relu(x)x = self.dropout2(self.bn2(self.fc2(x)))x = self.relu(x)x = self.bn3(self.fc3(x))x = self.relu(x)x = self.relu(self.bn4(self.fc4(x)))x = self.fc5(x)return xdef train(model,train_loader,lr,epochs):model.train()criterion = nn.CrossEntropyLoss()opt = optim.AdamW(model.parameters(),lr=lr,weight_decay=0.01)device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')model = model.to(device)for epoch in range(epochs):correct = 0for tx,ty in train_loader:tx,ty = tx.to(device),ty.to(device)y_pred = model(tx)loss = criterion(y_pred,ty)opt.zero_grad()loss.backward()opt.step()_,pred = torch.max(y_pred.data,dim=1)correct += (pred==ty).sum().item()acc = correct / len(train_loader.dataset)print(f'epoch:{epoch},loss:{loss.item():.4f},acc:{acc:.4f}')def eval(model,eval_loader):model.eval()criterion = nn.CrossEntropyLoss()device = torch.device('cuda' if torch.cuda.is_available() else 'cpu')model = model.to(device)eval_loss = 0correct = 0with torch.no_grad():for vx,vy in eval_loader:vx,vy = vx.to(device),vy.to(device)y_pred = model(vx)eval_loss += criterion(y_pred,vy)_,pred = torch.max(y_pred.data,dim=1)correct += (pred==vy).sum().item()eval_loss /= len(eval_loader.dataset)acc = 100*correct / len(eval_loader.dataset)print(f'loss:{eval_loss.item()},acc:{acc}')if __name__ == '__main__':train_loader,val_loader = build_data()model = CIFAR10Net(32*32*3,10)train(model,train_loader,lr=0.001,epochs=60)eval(model,val_loader)

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

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

相關文章

C語言的歷史

C 語言是一種 通用的、過程式的編程語言,由 丹尼斯里奇(Dennis Ritchie) 在 1972 年于貝爾實驗室開發。它以 高效、靈活、貼近硬件 而著稱,廣泛應用于系統軟件、嵌入式系統、驅動程序、游戲引擎、數據庫系統等底層開發領域。 C語…

jupyter使用

啟動win rcmdjupyter notebook創建python文件

linux 環境服務發生文件句柄泄漏導致服務不可用

問題描述:服務調用遠程rest接口 報錯,發生too many open files 異常,系統句柄資源耗盡,導致服務不可用。排查經過:1、針對報錯代碼進行本地構建,構造異常,并進行壓測。問題未復現2、經過討論分析…

手機錄制視頻時,硬編碼和軟編碼哪個質量高?(硬件編碼、軟件編碼)

文章目錄**1. 畫質對比**- **軟編碼**:- **硬編碼**:**2. 性能與功耗**- **軟編碼**:- **硬編碼**:**3. 實際應用中的權衡****4. 現代手機的折中方案****5. 如何選擇?****總結**在手機錄制視頻時, 軟編碼的…

IPv4與IPv6雙棧協議:網絡過渡的關鍵技術

為什么需要IPv4與IPv6共存? 在網絡技術的世界中,兼容性問題始終是最大的挑戰之一。IPv4和IPv6之間存在根本性的不兼容性,這意味著使用不同協議的設備無法直接通信。這種情況就像是兩個人試圖用完全不同的語言進行對話一樣。 目前的網絡現狀…

【牛客刷題】數字變換

一、題目描述 給出兩個數字a,ba,ba,b,aaa每次可以乘上一個大于1的正整數得到新的aa

MySQL 學習一 存儲結構和log

1.InnoDB邏輯存儲結構 表空間->段->區->頁->行->數據表空間:覆蓋了所有的數據和索引,系統表在系統表空間,還有默認表空間等 段:多個段組成表空間 區:多個區組成段,一般每個區的大小通常是1M…

TCP day39

六:C/S和B/S端 C/S:Client, server B/S:Browser server 1.cs 專用客戶端 bs 通用客戶端 2.協議不同 Cs 標準協議,自定義協議 Bs http 超文本傳輸 3.cs 功能復雜 bs 功能弱 4.bs 資源都在ser,有ser發送到cli cs 大部分資…

6 種無線傳輸照片從安卓到 Mac 的方法

將大量照片從安卓設備傳輸到電腦上,不僅可以備份照片,還能釋放設備存儲空間。雖然使用 USB 數據線可以在 Windows 電腦上輕松完成傳輸,但將安卓手機連接到 Mac 并非如此簡單。因此,許多用戶更傾向于無線傳輸照片從安卓到 Mac。您可…

在vscode 使用 remote-ssh

vscode安裝插件Remote-SSH,直接安裝即可 安裝完畢之后 在左下角有這個圖標 點擊之后選擇連接到主機然后選擇添加新鏈接之后輸入用戶名和主機地址 非默認端口使用 -p 端口號之后選擇第一個即可如果使用的是密碼,直接連接,然后輸入密碼即可如果使用的密鑰,則修改.ssh\config文件中…

RabbitMQ03——面試題

目錄 一、mq的作用和使用場景 二、mq的優點 2.1架構設計優勢 2.2功能特性優勢 2.3性能與可靠性優勢 2.4生態系統優勢 2.5對比優勢 三、mq的缺點 3.1性能與擴展性限制 3.2功能局限性 3.3運維復雜度 3.4與其他消息隊列的對比劣勢 四、mq相關產品,每種產品…

應用層攻防啟示錄:HTTP/HTTPS攻擊的精準攔截之道

一、七層攻擊的復雜性 # CC攻擊模擬工具(Python實現) import requests import threadingtarget_url "https://example.com/search?q"def cc_attack():while True:# 構造惡意搜索請求malicious_query "0" * 1000 # 長查詢參數try…

.net 警告【代碼 CS1998】此異步方法缺少 “await“ 運算符,將以同步方式運行。

【代碼 CS1998】此異步方法缺少 “await” 運算符,將以同步方式運行。請考慮使用 “await” 運算符等待非阻止的 API 調用,或者使用 “await Task.Run(…)” 在后臺線程上執行占用大量 CPU 的工作。在 VS 2022 中遇到的 CS1998 編譯器警告,表…

【自動駕駛黑科技】基于Frenet坐標系的車道變換軌跡規劃系統實現(附完整代碼)

1. 代碼結構概覽該代碼實現了一個車道變換軌跡規劃系統,包含兩個核心模塊:道路建模(EnhancedRoadModel):基于樣條曲線構建道路模型。軌跡規劃(LaneChangePlanner):根據障礙物狀態和道…

uni-calendar自定義簽到打卡顏色

uni-calendar自定義簽到打卡顏色,只需要將打卡的狀態添加到動態類class中即可 效果:在uni-modules >>> components >>> uni-calendar >>> uni-calendar-item.vue文件中,根據info對應的文字或者符號添加不同的clas…

浙江大學PTA程序設計C語言基礎編程練習題1-5

🌏個人博客主頁:意疏-CSDN博客 希望文章能夠給到初學的你一些啟發~ 如果覺得文章對你有幫助的話,點贊 關注 收藏支持一下筆者吧~ 閱讀指南:開篇說明題目一、厘米換算英寸題目二、然后是幾點題目三、 逆序…

catkin build的config設置指南[設置多種make模式或策略]

在本篇文章中,我們來盡可能詳細地深入探討 catkin config 的使用方法。這是掌握 catkin_tools 工作流的關鍵,能極大地提升你的開發效率和項目的規范性。 catkin config 的核心思想 首先,要理解它的核心思想:為你的 Catkin 工作空間…

Ubuntu掛載和取消掛載

在 Ubuntu 中,掛載(Mount)和取消掛載(Unmount)是管理存儲設備(如硬盤、U盤、ISO鏡像等)的常見操作。以下是詳細指南:1. 掛載(Mount) 1.1 查看可用存儲設備 ls…

Vue開發常用庫(含npm安裝命令)

Vue開發常用庫(含npm安裝命令) 核心生態系統:Vue Router - 官方路由管理器 npm install vue-router4 # Vue 3 npm install vue-router3 # Vue 2Pinia - 新一代狀態管理庫 npm install piniaVuex - 傳統狀態管理庫 npm install vuexnext …

[硬件電路-39]:激光光路的光信號處理、模擬電路的電信號處理、數字電路的電信號處理、軟件的信號處理,有哪些共通的操作、運算、變換?

激光光路、模擬電路、數字電路及軟件中的信號處理在操作、運算和變換層面存在顯著共性,這些共性體現了信號處理的核心邏輯在不同技術領域的通用性。以下是具體分析: 目錄 一、共通操作:信號處理的基礎動作 1、放大與衰減 2、濾波 3、調制…