2-4 Softmax 回歸的從零開始實現

就像我們從零開始實現線性回歸一樣, 我們認為softmax回歸也是重要的基礎,因此應該知道實現softmax回歸的細節。 本節我們將使用剛剛在2-3節中引入的Fashion-MNIST數據集, 并設置數據迭代器的批量大小為256

import torch
from IPython import display
from d2l import torch as d2lbatch_size = 256 # 每次隨機讀取256張圖片
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size) # 返回訓練集的iter迭代器和測試集的iter迭代器

初始化模型參數

和之前線性回歸的例子一樣,這里的每個樣本都將用固定長度的向量表示。 原始數據集中的每個樣本都是 28 × 28 28 \times 28 28×28的圖像。 本節將展平每個圖像,把它們看作長度為 784 784 784的向量(對于softmax回歸而言,我的輸入需要是一個向量)。 在后面的章節中,我們將討論能夠利用圖像空間結構的特征, 但現在我們暫時只把每個像素位置看作一個特征。(拉長以后,會損失掉很多空間信息)

回想一下,在softmax回歸中,我們的輸出與類別一樣多。 因為我們的數據集有 10 10 10個類別,所以網絡輸出維度為 10 10 10。 因此,權重將構成一個 784 × 10 784 \times 10 784×10的矩陣, 偏置將構成一個 1 × 10 1 \times 10 1×10的行向量(聯系softmax回歸那里的圖和公式例子來理解)。 與線性回歸一樣,我們將使用正態分布初始化我們的權重 W W W,偏置初始化為 0 0 0

num_inputs = 784  # softmax的輸入是長為784的行向量
num_outputs = 10  # 模型輸出的維度為10W = torch.normal(0, 0.01, size=(num_inputs, num_outputs), requires_grad=True)
# 將權重初始化成一個高斯隨機分布的值,均值為0,方差為0.01,行數為輸入的個數,列數為輸出的個數,requires_grad=True表示需要計算梯度
b = torch.zeros(num_outputs, requires_grad=True)
# 對每一個輸出,都需要一個偏移,所以偏移是一個長為10的向量,同樣,我們需要計算梯度

定義softmax操作

在實現softmax回歸模型之前,我們簡要回顧一下sum運算符如何沿著張量中的特定維度工作。 如前所述, 給定一個矩陣 X X X,我們可以對所有元素求和(默認情況下)。 也可以只求同一個軸上的元素,即同一列(軸 0 0 0)或同一行(軸 1 1 1)。 如果 X X X是一個形狀為 ( 2 , 3 ) (2, 3) (2,3)的張量,我們對列進行求和, 則結果將是一個具有形狀 ( 3 , ) (3,) (3,)的向量。 當調用sum運算符時,我們可以指定保持在原始張量的軸數,而不折疊求和的維度。 這將產生一個具有形狀 ( 1 , 3 ) (1, 3) (1,3)的二維張量。

X = torch.tensor([[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]])
X.sum(0, keepdim=True), X.sum(1, keepdim=True)
# 按照維度0來求和,那就是把我的形狀shape中的第0號元素從2變成了1
# 按照維度1來求和,那就是把我的形狀shape中第一個元素變成1,那么它就變成了一個2*1的列向量
# keepdim=True 表示還是一個2維的矩陣
# X.sum(0, keepdim=True) 按行求和
# X.sum(1, keepdim=True) 按列求和

在這里插入圖片描述
回想一下,實現softmax由三個步驟組成:

  1. 對每個項求冪(使用exp);

  2. 對每一行求和(小批量中每個樣本是一行),得到每個樣本的規范化常數;

  3. 將每一行除以其規范化常數,確保結果的和為1。

在查看代碼之前,我們回顧一下這個表達式:
在這里插入圖片描述
分母或規范化常數,有時也稱為配分函數(其對數稱為對數-配分函數)。 該名稱來自統計物理學中一個模擬粒子群分布的方程。

def softmax(X):X_exp = torch.exp(X) # 對每一個元素作指數計算partition = X_exp.sum(1, keepdim=True)  # 我們按照維度為1來求和,就是把每一行進行求和,keepdim=True保持二維矩陣的shapereturn X_exp / partition  # 這里應用了廣播機制

正如上述代碼,對于任何隨機輸入,我們將每個元素變成一個非負數。 此外,依據概率原理,每行總和為1。

X = torch.normal(0, 1, (2, 5))  # 初始化了一個均值為0,方差為1的,2行5列的矩陣X
X_prob = softmax(X)  # 把它放進softmax之后,它的形狀沒有發生變化
X_prob, X_prob.sum(1) # 按照行來做加法的話,會得到一個長為2的行向量,每一行的值為1,表示上面的概率每一行的和為1

在這里插入圖片描述
注意,雖然這在數學上看起來是正確的,但我們在代碼實現中有點草率。 矩陣中的非常大或非常小的元素可能造成數值上溢或下溢,但我們沒有采取措施來防止這點。


定義模型

定義softmax操作后,我們可以實現softmax回歸模型。 下面的代碼定義了輸入如何通過網絡映射到輸出。 注意,將數據傳遞到模型之前,我們使用reshape函數將每張原始圖像展平為向量。

def net(X):return softmax(torch.matmul(X.reshape((-1, W.shape[0])), W) + b)# 對于輸入X,我們需要的是一個批量大小 x 輸入維數的矩陣,所以我們把它reshape成一個2d的矩陣,-1表示讓它自己算一下,這個維度表示批量大小# W.shape[0]是784# X被reshape成一個256*784的矩陣# 然后我們再對X和W進行矩陣乘法# 通過廣播機制,加上我們的偏移# 最后放進softmax里面# 拿到一個所有的元素值大于0,而且行和為1的輸出

定義損失函數

接下來,我們實現交叉熵損失函數。 這可能是深度學習中最常見的損失函數,因為目前分類問題的數量遠遠超過回歸問題的數量
在講代碼之前,我們補一個細節,怎么樣在我的預測值里面根據我的標號把我們對應的預測值拿出來

y = torch.tensor([0, 2]) # 創建一個長度為2的向量,這里表示兩個真實的標號,這里標號的含義是該樣本被分為第幾類!就是實際該樣本屬于下標為幾的類
y_hat = torch.tensor([[0.1, 0.3, 0.6], [0.3, 0.2, 0.5]]) # 對2個樣本作3類預測
y_hat[[0, 1], y] 

在這里插入圖片描述
解釋:

  • 對y_hat中的第0個樣本,拿出下標為0的預測值
  • 對y_hat中的第1個樣本,拿出下標為2的預測值

現在我們只需一行代碼就可以實現交叉熵損失函數。

def cross_entropy(y_hat, y):return - torch.log(y_hat[range(len(y_hat)), y])# range(len(y_hat)) 生成一個0-y_hat-1的行向量,也就是說對y_hat中的每一行(每一個樣本)而言# 拿出來對應真實標號的預測值# 取個log# 求負數cross_entropy(y_hat, y)

在這里插入圖片描述
2.3026是樣本0的損失,0.6931是樣本1的損失,損失都是大于0的。

分類精度

因為我們做的是分類問題,所以我們要判斷說預測的類別和真實的類別是不是正確的。
我們這里實現一個小函數,說給定我們的預測值y_hat和我們的真實值y,我們來計算我們分類正確的類別數。

def accuracy(y_hat, y):"""計算預測正確的數量"""if len(y_hat.shape) > 1 and y_hat.shape[1] > 1: # 如果y_hat是一個二維矩陣的話,列數也大于1y_hat = y_hat.argmax(axis=1)  # 按照每一行求argmax,每一行中元素值最大的那個下標,存到y_hat里面,這就是我預測的分類類別cmp = y_hat.type(y.dtype) == y   # 可能我的y_hat和我的y數據類型不一樣,把y_hat轉成y的數據類型,作比較,變成一個bool的tensorreturn float(cmp.type(y.dtype).sum())  # 把結果轉成和y一樣的數據類型,求和,再轉成浮點數accuracy(y_hat, y) / len(y) # 找出來預測正確的樣本數 除以 y的長度,就是預測正確的概率
# 為什么除以y的長度,y的長度就是真實需要預測樣本的總數

在這里插入圖片描述
同樣,對于任意數據迭代器data_iter可訪問的數據集, 我們可以評估在任意模型net的精度。

def evaluate_accuracy(net, data_iter):  """計算在指定數據集上模型的精度"""if isinstance(net, torch.nn.Module):  # 如果是用torch nn實現的模型net.eval()  # 將模型設置為評估模式,意思是說不要計算梯度了,我們只做一個前向傳遞metric = Accumulator(2)  # 正確預測數、預測總數with torch.no_grad():for X, y in data_iter:metric.add(accuracy(net(X), y), y.numel())# 先把X放到net里面算出評測值# 然后計算所有的預測正確的樣本數# y.numel() 樣本總數# 放進一個Accumulator累加器里return metric[0] / metric[1]  # metric[0]分類正確的樣本數 metric[1]總樣本數 做除法,就能算出模型的精度了 

這里定義一個實用程序類Accumulator,用于對多個變量進行累加。 在上面的evaluate_accuracy函數中, 我們在Accumulator實例中創建了2個變量, 分別用于存儲正確預測的數量和預測的總數量。 當我們遍歷數據集時,兩者都將隨著時間的推移而累加。

class Accumulator:  """在n個變量上累加"""def __init__(self, n):self.data = [0.0] * ndef add(self, *args):self.data = [a + float(b) for a, b in zip(self.data, args)]def reset(self):self.data = [0.0] * len(self.data)def __getitem__(self, idx):return self.data[idx]

訓練

在我們看過線性回歸實現, softmax回歸的訓練過程代碼應該看起來非常眼熟。 在這里,我們重構訓練過程的實現以使其可重復使用。 首先,我們定義一個函數來訓練一個迭代周期。 請注意,updater是更新模型參數的常用函數,它接受批量大小作為參數。 它可以是d2l.sgd函數,也可以是框架的內置優化函數。

def train_epoch_ch3(net, train_iter, loss, updater):  #@save"""訓練模型一個迭代周期(定義見第3章)"""# 將模型設置為訓練模式if isinstance(net, torch.nn.Module):       # 如果我是用nn 模塊net.train()                      # 告訴我的模型開始訓練模式,即告訴pytorch我要計算梯度# 訓練損失總和、訓練準確度總和、樣本數metric = Accumulator(3)for X, y in train_iter:# 計算梯度并更新參數y_hat = net(X)l = loss(y_hat, y)if isinstance(updater, torch.optim.Optimizer):# 使用PyTorch內置的優化器和損失函數updater.zero_grad()  # 先把梯度設成0l.mean().backward()  # 再計算梯度updater.step()   # 再更新一遍參數else:# 使用定制的優化器和損失函數l.sum().backward()   # 求和并算梯度updater(X.shape[0])metric.add(float(l.sum()), accuracy(y_hat, y), y.numel())   # 記錄一下分類的正確的個數# 返回訓練損失和訓練精度return metric[0] / metric[2], metric[1] / metric[2]

在展示訓練函數的實現之前,我們定義一個在動畫中繪制數據的實用程序類Animator, 它能夠簡化其余部分的代碼。
這是一個小動畫,可以讓我們看到模型在訓練中的變化。

class Animator:"""在動畫中繪制數據"""def __init__(self, xlabel=None, ylabel=None, legend=None, xlim=None,ylim=None, xscale='linear', yscale='linear',fmts=('-', 'm--', 'g-.', 'r:'), nrows=1, ncols=1,figsize=(3.5, 2.5)):# 增量地繪制多條線if legend is None:legend = []d2l.use_svg_display()self.fig, self.axes = d2l.plt.subplots(nrows, ncols, figsize=figsize)if nrows * ncols == 1:self.axes = [self.axes, ]# 使用lambda函數捕獲參數self.config_axes = lambda: d2l.set_axes(self.axes[0], xlabel, ylabel, xlim, ylim, xscale, yscale, legend)self.X, self.Y, self.fmts = None, None, fmtsdef add(self, x, y):# 向圖表中添加多個數據點if not hasattr(y, "__len__"):y = [y]n = len(y)if not hasattr(x, "__len__"):x = [x] * nif not self.X:self.X = [[] for _ in range(n)]if not self.Y:self.Y = [[] for _ in range(n)]for i, (a, b) in enumerate(zip(x, y)):if a is not None and b is not None:self.X[i].append(a)self.Y[i].append(b)self.axes[0].cla()for x, y, fmt in zip(self.X, self.Y, self.fmts):self.axes[0].plot(x, y, fmt)self.config_axes()display.display(self.fig)display.clear_output(wait=True)

接下來我們實現一個訓練函數, 它會在train_iter訪問到的訓練數據集上訓練一個模型net。 該訓練函數將會運行多個迭代周期(由num_epochs指定)。 在每個迭代周期結束時,利用test_iter訪問到的測試數據集對模型進行評估。 我們將利用Animator類來可視化訓練進度。

def train_ch3(net, train_iter, test_iter, loss, num_epochs, updater):  #@save"""訓練模型(定義見第3章)"""animator = Animator(xlabel='epoch', xlim=[1, num_epochs], ylim=[0.3, 0.9],legend=['train loss', 'train acc', 'test acc']) # 上面這個是用來可視化的,可以忽略# 掃n遍數據for epoch in range(num_epochs):train_metrics = train_epoch_ch3(net, train_iter, loss, updater)  # 訓練一次,更新我們的模型test_acc = evaluate_accuracy(net, test_iter)   # 在測試數據集上評估精度animator.add(epoch + 1, train_metrics + (test_acc,))  # 可視化的顯示一遍train_loss, train_acc = train_metricsassert train_loss < 0.5, train_lossassert train_acc <= 1 and train_acc > 0.7, train_accassert test_acc <= 1 and test_acc > 0.7, test_acc

作為一個從零開始的實現,我們使用小批量隨機梯度下降來優化模型的損失函數,設置學習率為0.1

lr = 0.1def updater(batch_size):return d2l.sgd([W, b], lr, batch_size)

現在,我們訓練模型10個迭代周期。 請注意,迭代周期(num_epochs)和學習率(lr)都是可調節的超參數。 通過更改它們的值,我們可以提高模型的分類精度。

num_epochs = 10
train_ch3(net, train_iter, test_iter, cross_entropy, num_epochs, updater)

在這里插入圖片描述
隨著訓練的進行,精度在不斷的上升,損失在下降。


預測

現在訓練已經完成,我們的模型已經準備好對圖像進行分類預測。 給定一系列圖像,我們將比較它們的實際標簽(文本輸出的第一行)和模型預測(文本輸出的第二行)。

def predict_ch3(net, test_iter, n=6):"""預測標簽"""for X, y in test_iter:breaktrues = d2l.get_fashion_mnist_labels(y)preds = d2l.get_fashion_mnist_labels(net(X).argmax(axis=1))titles = [true +'\n' + pred for true, pred in zip(trues, preds)]d2l.show_images(X[0:n].reshape((n, 28, 28)), 1, n, titles=titles[0:n])predict_ch3(net, test_iter)

在這里插入圖片描述


小結

  • 借助softmax回歸,我們可以訓練多分類的模型。

  • 訓練softmax回歸循環模型與訓練線性回歸模型非常相似:先讀取數據,再定義模型和損失函數,然后使用優化算法訓練模型。大多數常見的深度學習模型都有類似的訓練過程。

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

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

相關文章

【chtagpt】pytorch中的方法對象和屬性

文章目錄 定義一個簡單的類屬性和方法對象的區別PyTorch 張量中的屬性和方法對象進一步解釋總結self.value value 的解釋示例解釋總結 為了更好地理解方法對象和屬性&#xff0c;我們可以通過一個簡單的類來演示這兩者的區別及其用法。 定義一個簡單的類 我們定義一個名為 My…

開發個人Go-ChatGPT--1 項目介紹

開發個人Go-ChatGPT--1 項目介紹 開發個人Go-ChatGPT--1 項目介紹知識點大綱文章目錄項目地址 開發個人Go-ChatGPT–1 項目介紹 本文將以一個使用Ollama部署的ChatGPT為背景&#xff0c;主要還是介紹和學習使用 go-zero 框架&#xff0c;開發個人Go-ChatGPT的服務器后端&#…

主從復制原理及操作

主從復制的概念 主從復制是一種在數據庫系統中常用的數據備份和讀取擴展技術&#xff0c;通過將一個數據庫服務器&#xff08;主服務器&#xff09;上的數據變更自動同步到一個或多個數據庫服務器&#xff08;從服務器&#xff09;上&#xff0c;以此來實現數據的冗余備份、讀…

解決video.js在demo中可以播放,在已有項目中無限waiting的問題

video.js的是有推薦的和react一起使用的寫法的&#xff1a;https://videojs.com/guides/react/ 但是這個寫法在demo中可以正常播放&#xff0c;在放在現有的項目中則播不出來&#xff0c;也不報錯&#xff0c;就是log里顯示on waiting后就什么動靜都沒有了&#xff0c;頁面顯示…

貝葉斯學習中先驗分布的詳細解釋

在貝葉斯學習中&#xff0c;先驗分布&#xff08;Prior Distribution&#xff09;是一個非常重要的概念。它代表了在觀察到任何數據之前&#xff0c;對未知參數的初始信念或知識。先驗分布的選擇通常基于領域知識、歷史數據或者純粹的假設。 文章目錄 先驗分布的含義先驗分布的…

dtpay聚合支付系統在跨境支付場景中技術及業務方案

1 什么是跨境支付 我們從兩個維度來分析什么是跨境支付&#xff0c;第一個維度我們從資金流向分析&#xff0c;國內的消費者在境外進行消費對于國內資金流來說這屬于資金流出&#xff0c;這是跨境支付的第一種應用場景。第二個場景國外游客在國內進行消費&#xff0c;這屬于資…

昇思25天學習打卡營第11天 | LLM原理和實踐:基于MindSpore實現BERT對話情緒識別

1. 基于MindSpore實現BERT對話情緒識別 1.1 環境配置 # 實驗環境已經預裝了mindspore2.2.14&#xff0c;如需更換mindspore版本&#xff0c;可更改下面mindspore的版本號 !pip uninstall mindspore -y !pip install -i https://pypi.mirrors.ustc.edu.cn/simple mindspore2.2…

js的作用域鏈

function test(){} 運行期上下文&#xff1a;當函數執行時&#xff0c;會創建一個稱為執行期上下文的內部對象。一個執行期上下文定義了一個函數執行時的環境&#xff0c;函數每次執行時對應的執行上下文都是 獨一無二的&#xff0c;所以多次調用一個函數對導致創建多個執行上下…

Linux 安裝pdfjam (PDF文件尺寸調整)

跟Ghostscript搭配使用&#xff0c;這樣就可以將不同尺寸的PDF調整到相同尺寸合并了。 在 CentOS 上安裝 pdfjam 需要安裝 TeX Live&#xff0c;因為 pdfjam 是基于 TeX Live 的。以下是詳細的步驟來安裝 pdfjam&#xff1a; ### 步驟 1: 安裝 EPEL 倉庫 首先&#xff0c;安…

springboot集成tika解析word,pdf,xls文件文本內容

介紹 Apache Tika 是一個開源的內容分析工具包&#xff0c;用于從各種文檔格式中提取文本和元數據。它支持多種文檔類型&#xff0c;包括但不限于文本文件、HTML、PDF、Microsoft Office 文檔、圖像文件等。Tika 的主要功能包括內容檢測、文本提取和元數據提取。 官網 https…

python入門詳細介紹

Python 是一種廣泛使用的高級編程語言&#xff0c;以其清晰的語法和代碼可讀性而聞名。它支持多種編程范式&#xff0c;包括面向對象、命令式、函數式和過程式編程。Python 由 Guido van Rossum 于1989年底發明&#xff0c;第一個公開發行版發行于1991年。 Python 的特點&…

java-初始化Map快捷裝數據

*單個Map創建 Map<String, String> stringStringMap Collections.singletonMap("reason", "同意");使用匿名類初始化Map List<Map<String,Object>> mapListnew ArrayList<>();mapList.add(new HashMap<String, Object>() {…

基于STM32F407ZG的FreeRTOS移植

1.從FreeRTOS官網中下載源碼 2、簡單分析FreeRTOS源碼目錄結構 2.1、簡單分析FreeRTOS源碼根目錄 &#xff08;1&#xff09;Demo&#xff1a;是官方為一些單片機移植FreeRTOS的例程 &#xff08;2&#xff09;License&#xff1a;許可信息 &#xff08;3&#xff09;Sourc…

《中國品牌網》揭秘格行品牌崛起之路:如何從混亂市場中殺出重圍,領跑未來?

在隨身WiFi行業亂象叢生的背景下&#xff0c;格行品牌憑借其獨特的經營理念和長期主義的精神&#xff0c;逐漸嶄露頭角&#xff0c;成為行業的領跑者。近日&#xff0c;《中國品牌網》記者專訪了格行品牌的創始人劉永先先生&#xff0c;就他的經營理念、市場策略以及未來展望進…

如何在 Odoo 16 中對 Many2Many 字段使用 Group by

Many2many 字段與 Many2one 字段類似,因為它們在模型之間建立了新的關系。在Odoo 16中,您無法按 many2many 字段分組,因為可以使用 many2many 記錄選擇任何記錄。當您使用 many2many 字段給出 group by 過濾器時,您將遇到斷言錯誤。 介紹如何在 Odoo 16 中使用 Many2Many…

AIGC | 為機器學習工作站安裝NVIDIA 4070 Ti Super顯卡驅動

[ 知識是人生的燈塔&#xff0c;只有不斷學習&#xff0c;才能照亮前行的道路 ] 0x00 前言簡述 話接上篇《AIGC | Ubuntu24.04桌面版安裝后必要配置》文章&#xff0c;作為作者進行機器學習的基礎篇&#xff08;筑基期&#xff09;&#xff0c;后續將主要介紹機器學習環境之如何…

6-google::protobuf命名空間下常用的C++ API----repeated_field.h

#include <google/protobuf/repeated_field.h> namespace google::protobuf 所生成的協議消息類使用RepeatedField和RepeatedPtrField來操作重復字段。 這些類與STL的vector非常相似&#xff0c;但包含了許多優化&#xff0c;這些優化被發現特別適用于協議緩沖區的情況。…

【優化論】基本概念與細節

優化論&#xff08;Optimization Theory&#xff09;是數學和計算機科學中一個重要的分支&#xff0c;旨在尋找給定問題的最優解。這個領域的應用非常廣泛&#xff0c;從經濟學、工程學到機器學習、金融等各個領域都有其蹤跡。我們可以通過一系列直觀的比喻來理解優化論的基本概…

Python編譯器的選擇

了解如何使用一個集成開發環境&#xff08;IDE&#xff09;對于 Python 編程是非常重要的。IDE 提供了代碼編輯、運行、調試、版本控制等多種功能&#xff0c;可以極大地提升開發效率。以下是一些流行的 Python IDE 和代碼編輯器的介紹&#xff0c;以及如何開始使用它們&#x…

Python + 在線 + 文生音,音轉文(中文文本轉為英文語音,語音轉為中文文本)

開源模型 平臺&#xff1a;https://huggingface.co/ars-語言轉文本: pipeline("automatic-speech-recognition", model"openai/whisper-large-v3", device0 ) hf: https://huggingface.co/openai/whisper-large-v3 github: https://github.com/openai/wh…