深度學習計算(深度學習-李沐-學習筆記)

層和塊

單一輸出的線性模型:單個神經網絡 (1)接受一些輸入; (2)生成相應的標量輸出; (3)具有一組相關?參數(parameters),更新這些參數可以優化某目標函數。

多個輸出的網絡:像單個神經元一樣,層(1)接受一組輸入, (2)生成相應的輸出, (3)由一組可調整參數描述。 當我們使用softmax回歸時,一個單層本身就是模型。?

多層感知機:整個模型及其組成層都是這種架構。 整個模型接受原始輸入(特征),生成輸出(預測), 并包含一些參數(所有組成層的參數集合)。??同樣,每個單獨的層接收輸入(由前一層提供), 生成輸出(到下一層的輸入),并且具有一組可調參數, 這些參數根據從下一層反向傳播的信號進行更新。

神經網絡塊:塊(block)可以描述單個層、由多個層組成的組件或整個模型本身。 使用塊進行抽象的一個好處是可以將一些塊組合成更大的組件, 這一過程通常是遞歸的。

從編程的角度來看,塊由(class)表示。 它的任何子類都必須定義一個將其輸入轉換為輸出的前向傳播函數, 并且必須存儲任何必需的參數。 注意,有些塊不需要任何參數。 最后,為了計算梯度,塊必須具有反向傳播函數

下面的代碼生成一個網絡,其中包含一個具有256個單元和ReLU激活函數的全連接隱藏層, 然后是一個具有10個隱藏單元且不帶激活函數的全連接輸出層

import torch
from torch import nn
from torch.nn import functional as Fimport torch 
from torch import nn
from torch.nn import functional as F# 定義網絡
net = nn.Sequential(nn.Linear(20, 256),  # 全連接層,輸入維度20,輸出維度256nn.ReLU(),           # ReLU激活函數nn.Linear(256, 10)   # 輸出層,輸出維度10(不帶激活函數)
)# 創建一個形狀為(2, 20)的輸入張量
X = torch.rand(2, 20)# 打印輸出
print(net(X))

自定義塊

實現我們自定義塊之前,我們簡要總結一下每個塊必須提供的基本功能。

  1. 輸入數據作為其前向傳播函數的參數

  2. 通過前向傳播函數來生成輸出。請注意,輸出的形狀可能與輸入的形狀不同。例如,我們上面模型中的第一個全連接的層接收一個20維的輸入,但是返回一個維度為256的輸出。

  3. 計算其輸出關于輸入的梯度,可通過其反向傳播函數進行訪問。通常這是自動發生的。

  4. 存儲和訪問前向傳播計算所需的參數

  5. 根據需要初始化模型參數

# 自定義塊:一個多層感知機,其具有256個隱藏單元的隱藏層和一個10維輸出層
class MLP(nn.Module):# 用模型參數聲明層。這里,我們聲明兩個全連接的層def __init__(self):# 調用MLP的父類Module的構造函數來執行必要的初始化。# 這樣,在類實例化時也可以指定其他函數參數,例如模型參數params(稍后將介紹)super().__init__()self.hidden = nn.Linear(20, 256)  # 隱藏層self.out = nn.Linear(256, 10)  # 輸出層# 定義模型的前向傳播,即如何根據輸入X返回所需的模型輸出def forward(self, X):# 注意,這里我們使用ReLU的函數版本,其在nn.functional模塊中定義。return self.out(F.relu(self.hidden(X)))net = MLP()
print(net(X))

順序塊

為了構建我們自己的簡化的MySequential, 我們只需要定義兩個關鍵函數:

  1. 一種將塊逐個追加到列表中的函數;

  2. 一種前向傳播函數,用于將輸入按追加塊的順序傳遞給塊組成的“鏈條”。

# 順序塊
# __init__函數將每個模塊逐個添加到有序字典_modules中
class MySequential(nn.Module):def __init__(self, *args):super().__init__()for idx, module in enumerate(args):# 這里,module是Module子類的一個實例。我們把它保存在'Module'類的成員# 變量_modules中。_module的類型是OrderedDictself._modules[str(idx)] = moduledef forward(self, X):# OrderedDict保證了按照成員添加的順序遍歷它們for block in self._modules.values():X = block(X)return Xnet = MySequential(nn.Linear(20, 256), nn.ReLU(), nn.Linear(256, 10))
print(net(X))

在前向傳播函數中執行代碼

有時我們可能希望合并既不是上一層的結果也不是可更新參數的項, 我們稱之為常數參數(constant parameter)。

# 在前向傳播函數中執行代碼
class FixedHiddenMLP(nn.Module):def __init__(self):super().__init__()# 不計算梯度的隨機權重參數。因此其在訓練期間保持不變self.rand_weight = torch.rand((20, 20), requires_grad=False)self.linear = nn.Linear(20, 20)def forward(self, X):X = self.linear(X)# 使用創建的常量參數以及relu和mm函數X = F.relu(torch.mm(X, self.rand_weight) + 1)# 復用全連接層。這相當于兩個全連接層共享參數X = self.linear(X)# 控制流while X.abs().sum() > 1:X /= 2return X.sum()net = FixedHiddenMLP()
# print(net(X))# 嵌套塊
class NestMLP(nn.Module):def __init__(self):super().__init__()self.net = nn.Sequential(nn.Linear(20, 64), nn.ReLU(),nn.Linear(64, 32), nn.ReLU())self.linear = nn.Linear(32, 16)def forward(self, X):return self.linear(self.net(X))chimera = nn.Sequential(NestMLP(), nn.Linear(16, 20), FixedHiddenMLP())
chimera(X)

小結

  • 一個塊可以由許多層組成;一個塊可以由許多塊組成。

  • 塊可以包含代碼。

  • 塊負責大量的內部處理,包括參數初始化和反向傳播。

  • 層和塊的順序連接由Sequential塊處理。

參數管理

import torch
from torch import nn# 具有單隱藏層的多層感知機
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(), nn.Linear(8, 1))
X = torch.rand(size=(2, 4))
net(X)# 參數訪問
# 可以檢查第二個全連接層的參數
print(net[2].state_dict())# 目標參數
# 從第二個全連接層(即第三個神經網絡層)提取偏置, 
# 提取后返回的是一個參數類實例,并進一步訪問該參數的值
print(type(net[2].bias))
print(net[2].bias)
print(net[2].bias.data)# 還可以訪問每個參數的梯度
print(net[2].weight.grad == None)# 一次性訪問所有參數
print(*[(name, param.shape) for name, param in net[0].named_parameters()])
print(*[(name, param.shape) for name, param in net.named_parameters()])# 提供了另一種訪問網絡參數的方式
print(net.state_dict()['2.bias'].data)# 從嵌套塊收集參數
def block1():return nn.Sequential(nn.Linear(4, 8), nn.ReLU(),nn.Linear(8, 4), nn.ReLU())def block2():net = nn.Sequential()for i in range(4):# 在這里嵌套net.add_module(f'block {i}', block1())return netrgnet = nn.Sequential(block2(), nn.Linear(4, 1))
rgnet(X)print(rgnet)# 訪問第一個主要的塊中、第二個子塊的第一層的偏置項
rgnet[0][1][0].bias.data# 參數初始化
# 默認情況下,PyTorch會根據一個范圍均勻地初始化權重和偏置矩陣, 
# 這個范圍是根據輸入和輸出維度計算出的。 
# PyTorch的nn.init模塊提供了多種預置初始化方法。# 內置初始化
# 將所有權重參數初始化為標準差為0.01的高斯隨機變量, 且將偏置參數設置為0。
def init_normal(m):if type(m) == nn.Linear:nn.init.normal_(m.weight, mean=0, std=0.01)nn.init.zeros_(m.bias)
net.apply(init_normal)
net[0].weight.data[0], net[0].bias.data[0]# 還可以將所有參數初始化為給定的常數,比如初始化為1
def init_constant(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 1)nn.init.zeros_(m.bias)
net.apply(init_constant)
net[0].weight.data[0], net[0].bias.data[0]# 還可以對某些塊應用不同的初始化方法
# 使用Xavier初始化方法初始化第一個神經網絡層, 
# 然后將第三個神經網絡層初始化為常量值42
def init_xavier(m):if type(m) == nn.Linear:nn.init.xavier_uniform_(m.weight)
def init_42(m):if type(m) == nn.Linear:nn.init.constant_(m.weight, 42)net[0].apply(init_xavier)
net[2].apply(init_42)
print(net[0].weight.data[0])
print(net[2].weight.data)# 自定義初始化
def my_init(m):if type(m) == nn.Linear:print("Init", *[(name, param.shape)for name, param in m.named_parameters()][0])nn.init.uniform_(m.weight, -10, 10)m.weight.data *= m.weight.data.abs() >= 5net.apply(my_init)
net[0].weight[:2]# 我們始終可以直接設置參數
net[0].weight.data[:] += 1
net[0].weight.data[0, 0] = 42
net[0].weight.data[0]#  參數綁定
# 在多個層間共享參數: 我們可以定義一個稠密層,
# 然后使用它的參數來設置另一個層的參數
# 我們需要給共享層一個名稱,以便可以引用它的參數
shared = nn.Linear(8, 8)
net = nn.Sequential(nn.Linear(4, 8), nn.ReLU(),shared, nn.ReLU(),shared, nn.ReLU(),nn.Linear(8, 1))
net(X)
# 檢查參數是否相同
print(net[2].weight.data[0] == net[4].weight.data[0])
net[2].weight.data[0, 0] = 100
# 確保它們實際上是同一個對象,而不只是有相同的值
print(net[2].weight.data[0] == net[4].weight.data[0])

延后初始化

  • 我們定義了網絡架構,但沒有指定輸入維度。

  • 我們添加層時沒有指定前一層的輸出維度。

  • 我們在初始化參數時,甚至沒有足夠的信息來確定模型應該包含多少參數。

框架的延后初始化(defers initialization), 即直到數據第一次通過模型傳遞時,框架才會動態地推斷出每個層的大小。

在以后,當使用卷積神經網絡時, 由于輸入維度(即圖像的分辨率)將影響每個后續層的維數, 有了該技術將更加方便。 現在我們在編寫代碼時無須知道維度是什么就可以設置參數, 這種能力可以大大簡化定義和修改模型的任務。

自定義層

深度學習成功背后的一個因素是神經網絡的靈活性: 我們可以用創造性的方式組合不同的層,從而設計出適用于各種任務的架構。?

import torch
import torch.nn.functional as F
from torch import nn# 不帶參數的層:
# CenteredLayer類要從其輸入中減去均值。 
# 要構建它,我們只需繼承基礎層類并實現前向傳播功能
class CenteredLayer(nn.Module):def __init__(self):super().__init__()def forward(self, X):return X - X.mean()# 向該層提供一些數據,驗證它是否能按預期工作
layer = CenteredLayer()
layer(torch.FloatTensor([1, 2, 3, 4, 5]))# 可以將層作為組件合并到更復雜的模型中
net = nn.Sequential(nn.Linear(8, 128), CenteredLayer())# 向該網絡發送隨機數據后,檢查均值是否為0
Y = net(torch.rand(4, 8))
Y.mean()# 帶參數的層:
# 自定義版本的全連接層
# 該層需要兩個參數,一個用于表示權重,另一個用于表示偏置項
# 使用修正線性單元作為激活函數
# 該層需要輸入參數:in_units和units,分別表示輸入數和輸出數
class MyLinear(nn.Module):def __init__(self, in_units, units):super().__init__()self.weight = nn.Parameter(torch.randn(in_units, units))self.bias = nn.Parameter(torch.randn(units,))def forward(self, X):linear = torch.matmul(X, self.weight.data) + self.bias.datareturn F.relu(linear)# 實例化MyLinear類并訪問其模型參數
linear = MyLinear(5, 3)
linear.weight# 可以使用自定義層直接執行前向傳播計算
linear(torch.rand(2, 5))# 還可以使用自定義層構建模型
net = nn.Sequential(MyLinear(64, 8), MyLinear(8, 1))
net(torch.rand(2, 64))

小結

  • 我們可以通過基本層類設計自定義層。這允許我們定義靈活的新層,其行為與深度學習框架中的任何現有層不同。

  • 在自定義層定義完成后,我們就可以在任意環境和網絡架構中調用該自定義層。

  • 層可以有局部參數,這些參數可以通過內置函數創建。

讀寫文件

然而,有時我們希望保存訓練的模型, 以備將來在各種環境中使用(比如在部署中進行預測)。 此外,當運行一個耗時較長的訓練過程時, 最佳的做法是定期保存中間結果, 以確保在服務器電源被不小心斷掉時,我們不會損失幾天的計算結果。 因此,現在是時候學習如何加載和存儲權重向量和整個模型了。

import torch
from torch import nn
from torch.nn import functional as F# (1)加載和保存張量# 對于單個張量直接調用load和save函數讀寫
x = torch.arange(4)
torch.save(x, 'x-file') # save要求將要保存的變量作為輸入# 將存儲在文件中的數據讀回內存
x2 = torch.load('x-file')
x2# 可以存儲一個張量列表,然后把它們讀回內存
y = torch.zeros(4)
torch.save([x, y],'x-files')
x2, y2 = torch.load('x-files')
(x2, y2)# 可以寫入或讀取從字符串映射到張量的字典
mydict = {'x': x, 'y': y}
torch.save(mydict, 'mydict')
mydict2 = torch.load('mydict')
mydict2#  (2)加載和保存模型參數
# 深度學習框架提供了內置函數來保存和加載整個網絡
# 這將保存模型的參數而不是保存整個模型
# 為了恢復模型,需要用代碼生成架構, 然后從磁盤加載參數class MLP(nn.Module):def __init__(self):super().__init__()self.hidden = nn.Linear(20, 256)self.output = nn.Linear(256, 10)def forward(self, x):return self.output(F.relu(self.hidden(x)))net = MLP()
X = torch.randn(size=(2, 20))
Y = net(X)# 將模型的參數存儲在一個叫做“mlp.params”的文件中
torch.save(net.state_dict(), 'mlp.params')# 為了恢復模型,實例化了原始多層感知機模型的一個備份
# 不需要隨機初始化模型參數,而是直接讀取文件中存儲的參數
clone = MLP()
clone.load_state_dict(torch.load('mlp.params'))
clone.eval()# 兩個實例具有相同的模型參數,在輸入相同的X時, 兩個實例的計算結果應該相同
Y_clone = clone(X)
Y_clone == Y

小結

  • saveload函數可用于張量對象的文件讀寫。

  • 我們可以通過參數字典保存和加載網絡的全部參數。

  • 保存架構必須在代碼中完成,而不是在參數中完成。

GPU

下載NVIDIA驅動和CUDA?并按照提示設置適當的路徑。 當這些準備工作完成,就可以使用nvidia-smi命令來查看顯卡信息。

計算設備

在PyTorch中,CPU和GPU可以用torch.device('cpu')?和torch.device('cuda')表示。 應該注意的是,cpu設備意味著所有物理CPU和內存, 這意味著PyTorch的計算將嘗試使用所有CPU核心。 然而,gpu設備只代表一個卡和相應的顯存。 如果有多個GPU,我們使用torch.device(f'cuda:{i}')?來表示第塊GPU(i從0開始)。 另外,cuda:0cuda是等價的。

import torch
from torch import nntorch.device('cpu'), torch.device('cuda'), torch.device('cuda:1')# 可以查詢可用gpu的數量
torch.cuda.device_count()# 定義了兩個方便的函數, 
# 這兩個函數允許我們在不存在所需所有GPU的情況下運行代碼
def try_gpu(i=0):  #@save"""如果存在,則返回gpu(i),否則返回cpu()"""if torch.cuda.device_count() >= i + 1:return torch.device(f'cuda:{i}')return torch.device('cpu')def try_all_gpus():  #@save"""返回所有可用的GPU,如果沒有GPU,則返回[cpu(),]"""devices = [torch.device(f'cuda:{i}')for i in range(torch.cuda.device_count())]return devices if devices else [torch.device('cpu')]try_gpu(), try_gpu(10), try_all_gpus()# 張量與GPU
# 可以查詢張量所在的設備。 
# 默認情況下,張量是在CPU上創建的。
x = torch.tensor([1, 2, 3])
x.device
# 無論何時我們要對多個項進行操作, 它們都必須在同一個設備上# 存儲在GPU上
X = torch.ones(2, 3, device=try_gpu())
X# 在第二個GPU上創建一個隨機張量
Y = torch.rand(2, 3, device=try_gpu(1))
Y# 復制
Z = X.cuda(1)
print(X)
print(Z)# 數據在同一個GPU上(Z和Y都在),我們可以將它們相加
Y + Z# 假設變量Z已經存在于第二個GPU上。 如果我們還是調用Z.cuda(1)會發生什么?
#  它將返回Z,而不會復制并分配新內存。
Z.cuda(1) is Z # true# 神經網絡與GPU
# 神經網絡模型可以指定設備
# 下面將模型參數放在GPU上
net = nn.Sequential(nn.Linear(3, 1))
net = net.to(device=try_gpu())# 當輸入為GPU上的張量時,模型將在同一GPU上計算結果
net(X)# 確認模型參數存儲在同一個GPU上
net[0].weight.data.device # device(type='cuda', index=0)

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

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

相關文章

leetcode熱題——搜索二維矩陣Ⅱ

目錄 搜索二維矩陣Ⅱ 題目描述 題解 解法一:暴力搜索 C 代碼實現 復雜度分析 解法二:二分查找 C 代碼實現 復雜度分析 解法三:Z字形查找 算法核心思想 算法步驟詳解 C 代碼實現 復雜度分析 搜索二維矩陣Ⅱ 題目描述 編寫一個…

牛客 - 數組中的逆序對

描述 在數組中的兩個數字,如果前面一個數字大于后面的數字,則這兩個數字組成一個逆序對。輸入一個數組,求出這個數組中的逆序對的總數P。并將P對1000000007取模的結果輸出。 即輸出P mod 1000000007 數據范圍: 對于 50% 的數據, size≤104 s…

Linux 日志管理與時鐘同步詳解

Linux 日志管理與時鐘同步詳解 一、日志管理 1. 日志服務概述 Linux 系統中主要有兩種日志服務,分別負責臨時和永久日志的管理: systemd-journald:存儲臨時日志,服務器重啟后日志會丟失,無需手動配置rsyslog&#xff1…

個人如何做股指期貨?

本文主要介紹個人如何做股指期貨?個人參與股指期貨交易需要遵循一定的流程和規則,同時需充分了解其高風險、高杠桿的特點,并做好風險管理。個人如何做股指期貨?一、了解股指期貨基礎股指期貨是以股票價格指數為標的物的金融期貨合…

設計模式-單例模式 Java

模式概述 單例模式(Singleton Pattern)是設計模式中最基礎但應用最廣泛的創建型模式之一,確保一個類僅有一個實例,并提供一個全局訪問點。這種模式在需要全局唯一對象的場景中至關重要,如配置管理、線程池、數據庫連接…

RFID 系統行業前沿洞察:技術躍遷與生態重構

在物聯網與人工智能深度融合的時代,RFID(射頻識別)系統正經歷從 “單品識別工具” 到 “智能決策中樞” 的范式轉變。這一技術憑借其非接觸式數據采集、環境適應性強、全生命周期追溯等特性,在醫療、制造、農業、環保等領域引發連…

實現implements InitializingBean, DisposableBean 有什么用

在 Spring 框架中,實現 InitializingBean 和 DisposableBean 接口用于管理 Bean 的生命周期回調,分別控制 Bean 的初始化后和銷毀前行為。具體作用如下:1. InitializingBean 接口public interface InitializingBean {void afterPropertiesSet…

GitLab 18.2 發布幾十項與 DevSecOps 有關的功能,可升級體驗【一】

沿襲我們的月度發布傳統,極狐GitLab 發布了 18.2 版本,該版本帶來了議題和任務的自定義工作流狀態、新的合并請求主頁、新的群組概覽合規儀表盤、下載安全報告的 PDF 導出文件、中心化的安全策略管理(Beta)等幾十個重點功能的改進…

如何快速把Clickhouse數據同步到Mysql

直接使用Clickhouse官方支持的Mysql引擎表的方式! 一、首先創建Mysql引擎表: CREATE TABLE saas_analysis.t_page_view_new_for_write (id Int64,shop_id Nullable(Int64),session_id Nullable(String),client_id Nullable(String),one_id Nullable(Str…

Kafka 重復消費與 API 冪等消費解決方案

Kafka 是一個高性能的分布式消息系統,但消費者重啟、偏移量(offset)未正確提交或網絡問題可能導致重復消費。API 冪等性設計則用于防止重復操作帶來的副作用。本文從 Kafka 重復消費和 API 冪等性兩個方面提供解決方案,重點深入探…

win11推遲更新

1、按住WINR2、輸入以下命令:reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\WindowsUpdate\UX\Settings" /v FlightSettingsMaxPauseDays /t reg_dword /d 10000 /f3、點擊確定4、打開搜索框5、在搜索框里邊輸入更新,選擇檢查更新6、在暫停…

【uniapp】---- 使用 uniapp 實現視頻和圖片上傳且都可以預覽展示

1. 前言 接手得 uniapp 開發的微信小程序項目,新的開發需求是需要同時上傳圖片和視頻,但是之前的上傳都沒有進行封裝,都是每個頁面需要的時候單獨實現,現在新的需求,有多個地方都需要上傳圖片、視頻或語音等,這樣就需要封裝一個組件,然后發現部分地方使用了 uni-file-p…

(nice!!!) (LeetCode 每日一題) 2411. 按位或最大的最小子數組長度(位運算+滑動窗口)

2411. 按位或最大的最小子數組長度 思路&#xff1a;位運算滑動窗口&#xff0c;時間復雜度0(n*32)。 **遍歷每一個元素nums[i]&#xff0c;然后看能否改變它前面的元素nums[j]&#xff08; j<i &#xff09;&#xff0c; 當(nums[j]|nums[i])nums[j]時&#xff0c;說明當前…

算法競賽階段二-數據結構(36)數據結構雙向鏈表模擬實現

//#include<bits/stdc.h> #include<iostream> using namespace std; const int N1e510; //定義 int e[N],pre[N],ne[N],h,id; int mp[N]; //頭插 // 兵 y // x void push_front (int x) {id;e[id]x;mp[x]id;pre[id]h;ne[id]ne[h];//先修改新節點…

津發科技帶你了解皮膚電信號中的SCL與SCR

皮膚電&#xff08;Electrodermal Activity, EDA&#xff09;作為一種非常容易獲取的基本生理信號&#xff0c;可以很好地量化我們的情緒反應&#xff0c;被廣泛應用于情感識別研究中。它代表機體受到刺激時皮膚電傳導的變化。皮膚電反應作為交感神經系統功能的直接指標&#x…

spark的broadcast variables

在 Spark 中&#xff0c;廣播變量&#xff08;Broadcast Variables&#xff09; 是一種特殊類型的共享變量&#xff0c;用于高效地在集群中的所有節點間分發大型只讀數據集。它解決了 Spark 任務中頻繁傳輸重復數據的性能問題&#xff0c;特別適用于需要在多個任務中重用相同數…

Python爬蟲實戰:研究Haul庫相關技術構建電商數據采集與分析系統

1. 引言 1.1 研究背景與意義 隨著電子商務的迅速發展,電商平臺上的商品數據呈現爆炸式增長。這些數據蘊含著豐富的商業價值,如消費者行為分析、市場趨勢預測、競爭對手監測等。然而,如何從海量的電商數據中獲取有價值的信息,成為當前電商企業面臨的重要挑戰。 網絡爬蟲技…

Java:高頻面試知識分享1

一、Java 語言核心特性&#xff08;面向對象編程&#xff09;核心知識點梳理&#xff1a;面向對象三大特性&#xff1a;封裝&#xff1a;隱藏對象內部實現&#xff0c;通過 public 方法暴露接口&#xff08;例&#xff1a;類的 private 字段 get/set 方法&#xff09;。繼承&a…

MybatisPlus-核心功能

目錄 條件構造器 QueryWrapper UpdateWrapper LambdaQueryWrapper 自定義SQL 基本用法 多表關聯 Service接口 CRUD 基本用法 Lambda 批量新增 條件構造器 除了新增以外&#xff0c;修改、刪除、查詢的SQL語句都需要指定where條件。因此BaseMapper中提供的相關方法…

RHCE綜合項目:分布式LNMP私有博客服務部署

一、項目概述本次項目基于LNMP&#xff08;linux&#xff0c;nginx&#xff0c;mariadb&#xff0c;php&#xff09;搭建了一個私有的博客平臺&#xff0c;本篇博客詳細記錄了該博客平臺的服務部署全流程。在該項目中&#xff0c;使用了兩臺linux&#xff08;openeuler&#xf…