具體流程參考教程:MindSpore快速入門 MindSpore 接口文檔
注:本文章記錄的是我在開發(fā)過程中的學習筆記,僅供參考學習,歡迎討論,但不作為開發(fā)教程使用。

def datapipe(dataset, batch_size):
'''
數據處理流水線
'''
image_transform = [
vision.Rescale(1.0 / 255.0, 0), # 縮放 output = image * rescale + shift.
vision.Normalize(mean=(0.1307,), std=(0.3081,)), # 根據平均值和標準偏差對輸入圖像進行歸一化
vision.HWC2CHW() # 轉換為NCHW格式
]
label_transform = transforms.TypeCast(mindspore.int32) # 轉為mindspore的int32格式
dataset = dataset.map(image_transform, 'image') # 對各個圖像按照流水線處理
dataset = dataset.map(label_transform, 'label') # 對各個標簽轉換為int32
dataset = dataset.batch(batch_size)
return dataset這段代碼中對輸入圖片進行了縮放、歸一化和格式轉換三個操作,按照流水線運行。
流水線操作數據流水線處理的介紹:【AI設計模式】03-數據處理-流水線(Pipeline)模式
總結而言,海量數據下,流水線模式可以實現(xiàn)高效的數據處理,當然也會占用更多的CPU和內存資源。
mindspore下dataset的map操作:第一個參數是處理函數列表,第二個參數是需要處理的列。
map函數會將數據集中第二個參數的指定的列作為輸入,調用第一個參數的處理函數執(zhí)行處理,如果有多個處理函數,上一個函數的輸出作為下一個函數的輸入。
NCHW
缺點:必須等所有通道輸入準備好才能得到最終輸出結果,需要占用較大的臨時空間。
優(yōu)點:是 Nvidia cuDNN 默認格式,使用 GPU 加速時用 NCHW 格式速度會更快。(這個是什么原因呢?沒找到資料_(:з」∠)_)
NHWC
缺點:GPU 加速較NCHW更慢
優(yōu)點:訪存局部性更好(每三個輸入像素即可得到一個輸出像素)
參考文章:【深度學習框架輸入格式】NCHW還是NHWC?
為什么pytorch中transforms.ToTorch要把(H,W,C)的矩陣轉為(C,H,W)?
class Network(nn.Cell):
'''
Network model
'''
def __init__(self):
super().__init__()
self.flatten = nn.Flatten()
self.dense_relu_sequential = nn.SequentialCell(
nn.Dense(28*28, 512),
nn.ReLU(),
nn.Dense(512, 512),
nn.ReLU(),
nn.Dense(512, 10)
)
def construct(self, x):
x = self.flatten(x)
logits = self.dense_relu_sequential(x)
return logits基類mindspore的模型基類是mindspore.nn.Cell
pytorch的模型基類是torch.nn.Module
mindspore的全連接層是mindspore.nn.Dense
pytorch的全連接層是torch.nn.Linear
mindspore的順序容器是mindspore.nn.SequentialCell
pytorch的順序容器是torch.nn.Sequential
mindspore的前向傳播函數(要執(zhí)行的計算邏輯)基類函數為construct(self, xxx)
pytorch的前向傳播函數基類函數為forward(self, xxx)
my_loss_fn = nn.CrossEntropyLoss()
my_optimizer = nn.SGD(model.trainable_params(), 1e-2)交叉熵:把來自一個分布q的消息使用另一個分布p的最佳代碼傳達方式計算得到的平均消息長度,即為交叉熵。針對交叉熵,這個文章講的較好:損失函數:交叉熵詳解
mindspore的交叉熵函數和pytorch類似:
前者是mindspore.nn.CrossEntropyLoss(),后者是torch.nn.CrossEntropyLoss()
def train(model_train, dataset, loss_fn, optimizer):
'''
訓練函數
'''
# Define forward function
def forward_fn(data, label):
logits = model_train(data)
loss = loss_fn(logits, label)
return loss, logits
# Get gradient function
grad_fn = ops.value_and_grad(forward_fn, None, optimizer.parameters, has_aux=True)
# Define function of one-step training
def train_step(data, label):
(loss, _), grads = grad_fn(data, label)
loss = ops.depend(loss, optimizer(grads))
return loss
size = dataset.get_dataset_size()
model_train.set_train()
for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):
loss = train_step(data, label)
if batch % 100 == 0:
loss, current = loss.asnumpy(), batch
print(f"loss: {loss:>7f} [{current:>3d}/{size:>3d}]")value_and_grad官網對value_and_grad函數的介紹如下:mindspore.ops.value_and_grad
按照官網的描述,這個函數的作用是:生成求導函數,用于計算給定函數的正向計算結果和梯度。
我們需要給這個函數傳入模型的正向傳輸函數和待求導的參數
其中模型的正向傳輸函數需要封裝一下,返回loss的計算, 用于后續(xù)優(yōu)化器的梯度計算;
待求導的參數可以寫為model.trainable_params(),也可以由優(yōu)化器提供(optimizer.parameters),因為優(yōu)化器初始化時已經傳入需要求導的參數。
總之,這個接口返回的是一個函數,函數的作用是把正向傳播、反向傳播的整個流程走一遍,最后的輸出為正向傳輸函數的返回值+待求導參數的梯度值
在訓練時使用到了depend算子,官網對Depend函數的介紹如下:mindspore.ops.Depend
# Define function of one-step training
def train_step(data, label):
(loss, _), grads = grad_fn(data, label)
loss = ops.depend(loss, optimizer(grads))
return loss經詢問分析,使用depend算子的原因是,在靜態(tài)圖模式下,函數執(zhí)行的先后順序可能會被優(yōu)化,這就可能存在loss在grad_fn(value_and_grad)之前就被返回使用的情況,導致返回的loss不正確。
因此通過使用depend算子,來保證loss的返回動作在optimizer之后執(zhí)行,而optimizer的輸入依賴grad_fn,因此optimizer一定在grad_fn之后執(zhí)行,這就保證了depend返回的loss確實是經過grad_fn計算的最新結果。
當然,mindspore也是支持動態(tài)圖模式的,只需加一行代碼:
# 設置為動態(tài)圖模式
mindspore.set_context(mode=mindspore.PYNATIVE_MODE)
# 設置為靜態(tài)圖模式
# mindspore.set_context(mode=mindspore.GRAPH_MODE)
model = Network()
print(model)然后訓練函數就可以這么寫:
def train_step(data, label):
(loss, _), grads = grad_fn(data, label)
optimizer(grads)
return loss但是實測,動態(tài)圖模式下,訓練速度相比靜態(tài)圖慢了很多。
關于mindspore動態(tài)圖和靜態(tài)圖模式的介紹,可看這個官方文檔:動靜態(tài)圖
各個文章在介紹梯度下降法時,通常介紹的是批量梯度下降法,但是訓練模型時用的最多的是小批量梯度下降法。這里先講下批量梯度下降、隨機梯度下降和小批量梯度下降的區(qū)別。
批量梯度下降批量梯度下降法的流程是:假設有1000個數據,經過正向計算,得到1000個計算結果,誤差函數的計算公式依賴這1000個計算結果;再對誤差函數進行反向傳播求導,得到模型里參數的梯度值;同樣地,對誤差函數求導得梯度,也依賴這1000個計算結果;最后基于學習率更新參數,然后進入下一輪訓練。
因此,標準的批量梯度下降,需要每次計算出1000個數據的正向傳播結果,才可以得到參數梯度值,然后下一輪訓練,重新計算1000個計算結果…這就存在大量的運算量,使得訓練容易變得非常耗時。
隨機梯度下降法的流程是,假設有1000個數據,我們隨機取1個數據,經過正向計算,得到1個計算結果,誤差函數的計算公式就只依賴這1個計算結果;然后反向傳播求導,得到基于1個計算結果的梯度值,最后基于學習率更新參數,然后進入下一輪訓練。下一輪訓練時,隨機取另1個數據,重復上述操作…
這種方法下,極大地降低了計算量,而且理論上,只要數據量夠大,數據足夠隨機,最后也總會下降到所需極值點,畢竟計算數據量小了很多,算得更快了,下降速度也會快很多。但是每次只依賴1個數據,就使得梯度的下降方向在整體方向上不穩(wěn)定,容易到處飄,最后的結果可能不會是全局最優(yōu)。
小批量梯度下降法的流程是:假設有1000個數據,我們隨機取100個數據,經過正向計算,得到100個計算結果,誤差函數的計算公式依賴這100個計算結果;然后反向傳播求導,得到基于100個計算結果的梯度值,最后基于學習率更新參數,然后進入下一輪訓練。下一輪訓練時,隨機取另100個數據,重復上述操作…
可以看出,小批量梯度下降 結合了 批量梯度下降 和 隨機梯度下降 的優(yōu)缺點,使得計算即不那么耗時,又保證參數更新路徑和結果相對穩(wěn)定。
mindspore的這個例子用的是小批量梯度下降,train_step每次輸入64個數據,然后前向傳播、計算梯度、更新參數,再進入下一個epoch,隨機取新的64個數據,重復訓練…
size = dataset.get_dataset_size()
model_train.set_train()
for batch, (data, label) in enumerate(dataset.create_tuple_iterator()):
loss = train_step(data, label)
if batch % 100 == 0:
loss, current = loss.asnumpy(), batch
print(f"loss: {loss:>7f} [{current:>3d}/{size:>3d}]")在將數據集進行datapipe后,返回的train_dataset和test_dataset都是以batch_size=64個為一組進行輸出的,此處dataset.get_dataset_size()返回的size是有多少組數據。測試集返回的size為938,表示一共有938組,每組64個圖片數據。實際上MNIST只有60000個測試集圖片,因此最后一組只有32個圖片。
運行結果Epoch 1
-------------------------------
loss: 2.303684 [ 0/938]
loss: 2.291476 [100/938]
loss: 2.273411 [200/938]
loss: 2.212310 [300/938]
loss: 1.969760 [400/938]
loss: 1.600426 [500/938]
loss: 1.004380 [600/938]
loss: 0.735266 [700/938]
loss: 0.672223 [800/938]
loss: 0.578563 [900/938]
Test:
Accuracy: 85.3%, Avg loss: 0.528851
Epoch 2
-------------------------------
loss: 0.384008 [ 0/938]
loss: 0.453575 [100/938]
loss: 0.277697 [200/938]
loss: 0.317674 [300/938]
loss: 0.294471 [400/938]
loss: 0.519272 [500/938]
loss: 0.253794 [600/938]
loss: 0.389252 [700/938]
loss: 0.383196 [800/938]
loss: 0.334877 [900/938]
Test:
Accuracy: 90.2%, Avg loss: 0.334850此處跑了兩輪訓練,可以看出,第一輪的938組數據的訓練過程中,參數快速調整至合理范圍(loss從2.3降低到0.5),但是第二輪的938組數據的訓練過程中,loss出現(xiàn)了上下波動(0.3->0.4->0.2->0.3…),即模型參數向當前數據組的梯度下降的方向走了一小步后,新的數據組算出的loss反而比之前還提高了。
這主要是因為當前數據組的梯度下降方向 無法代表 替他數據組/所有數據的梯度下降方向,當然也可能是學習率(步長)太大導致跨過了最低點,這個就具體問題具體分析了。
mindspore和pytorch在接口命名上存在區(qū)別,但是實際使用過程中,開發(fā)思路還是一致的。因此最關鍵的還是要熟悉深度學習的思路和流程,至于思路和代碼實現(xiàn)的映射,這就唯手熟爾。
你是否還在尋找穩(wěn)定的海外服務器提供商?創(chuàng)新互聯(lián)www.cdcxhl.cn海外機房具備T級流量清洗系統(tǒng)配攻擊溯源,準確流量調度確保服務器高可用性,企業(yè)級服務器適合批量采購,新人活動首月15元起,快前往官網查看詳情吧
當前題目:【mindspore】mindspore實現(xiàn)手寫數字識別-創(chuàng)新互聯(lián)
網頁路徑:http://chinadenli.net/article40/gdsho.html
成都網站建設公司_創(chuàng)新互聯(lián),為您提供自適應網站、商城網站、ChatGPT、微信小程序、品牌網站設計、面包屑導航
聲明:本網站發(fā)布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯(lián)系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創(chuàng)新互聯(lián)