深度學習模型的建構仰賴於層層堆積疊的網路結構,其中每一層都扮演著特定的角色。理解層級的初始化、前向傳播和反向傳播的機制,對於掌握深度學習的運作至關重要。本文將深入探討這些核心概念,並輔以程式碼示例,闡明如何在 Python 中實作這些功能。此外,損失函式的選擇和應用也是模型訓練的關鍵環節,本文也將詳細介紹如何定義和使用損失函式,以評估模型的效能並引導模型的最佳化方向。透過理解這些基礎概念,讀者將能夠更深入地理解神經網路的運作原理,並為進一步探索更複雜的深度學習模型奠定堅實的基礎。

Sigmoid 函式實作

import numpy as np

class Sigmoid:
    def __init__(self):
        pass

    def _output(self):
        return 1.0 / (1.0 + np.exp(-1.0 * self.input_))

    def _input_grad(self, output_grad):
        sigmoid_backward = self.output * (1.0 - self.output)
        input_grad = sigmoid_backward * output_grad
        return input_grad

層級建構

層級建構是神經網路中的基本單元。每個層級都包含了一系列的操作,包括啟用函式、權重矩陣乘法等。

層級類別

class Layer:
    def __init__(self, neurons):
        self.neurons = neurons
        self.operations = []

    def _setup_layer(self):
        # 初始化層級中的操作
        pass

    def forward(self, input_data):
        # 執行層級的前向傳播
        self.input_ = input_data
        for operation in self.operations:
            self.input_ = operation._output()
        self.output = self.input_
        return self.output

    def backward(self, output_grad):
        # 執行層級的反向傳播
        for operation in reversed(self.operations):
            output_grad = operation._input_grad(output_grad)
        return output_grad

    def _params(self):
        # 取得層級中的引數
        params = []
        for operation in self.operations:
            if isinstance(operation, ParamOperation):
                params.extend(operation.params)
        return params

    def _param_grads(self):
        # 取得層級中的引數梯度
        param_grads = []
        for operation in self.operations:
            if isinstance(operation, ParamOperation):
                param_grads.extend(operation.param_grads)
        return param_grads

啟用函式與層級的關係

啟用函式是層級中的基本組成部分。每個層級都包含了一系列的啟用函式,例如 Sigmoid、ReLU 等。這些啟用函式對輸入資料進行轉換,產生輸出結果。

在層級建構中,啟用函式通常與權重矩陣乘法等操作一起使用,以實作神經網路的前向傳播和反向傳播。

示例

# 建立一個具有 10 個神經元的層級
layer = Layer(10)

# 將 Sigmoid 啟用函式新增到層級中
layer.operations.append(Sigmoid())

# 執行層級的前向傳播
input_data = np.random.rand(10)
output = layer.forward(input_data)

# 執行層級的反向傳播
output_grad = np.random.rand(10)
input_grad = layer.backward(output_grad)

在這個示例中,我們建立了一個具有 10 個神經元的層級,並將 Sigmoid 啟用函式新增到層級中。然後,我們執行了層級的前向傳播和反向傳播,分別計算了輸出結果和輸入梯度。

神經網路層的初始化與前向傳遞

在神經網路的架構中,層(Layer)是一個非常重要的概念。每個層都會對輸入的資料進行特定的運算,然後將結果傳遞給下一個層。今天,我們要來探討層的初始化和前向傳遞的過程。

層的初始化

當我們建立一個新的層時,我們需要對其進行初始化。這個過程包括設定層的引數、梯度和運算。下面是層初始化的相關程式碼:

self.neurons = neurons
self.first = True
self.params: List[ndarray] = []
self.param_grads: List[ndarray] = []
self.operations: List[Operation] = []

在這裡,我們設定了層的神經元數量、是否為第一層、引數列表、梯度列表和運算列表。

層的前向傳遞

層的前向傳遞是指將輸入的資料傳遞給下一個層的過程。這個過程包括了對輸入資料進行特定的運算,然後將結果傳遞給下一個層。下面是層的前向傳遞的相關程式碼:

def forward(self, input_: ndarray) -> ndarray:
    if self.first:
        self._setup_layer(input_)
        self.first = False

在這裡,我們定義了前向傳遞的函式 forward。如果是第一層,我們會呼叫 _setup_layer 函式來設定層的引數和運算。然後,我們會將 first 屬性設為 False,表示這個層已經被設定好了。

層的設定

每個層都需要實作 _setup_layer 函式來設定自己的引數和運算。下面是 _setup_layer 函式的相關程式碼:

def _setup_layer(self, num_in: int) -> None:
    raise NotImplementedError()

在這裡,我們定義了 _setup_layer 函式,但是沒有實作它。這是因為每個層都需要自己實作這個函式來設定自己的引數和運算。

圖表翻譯:

  graph LR
    A[輸入] --> B[層]
    B --> C[前向傳遞]
    C --> D[設定層]
    D --> E[傳遞給下一個層]

在這個圖表中,我們可以看到輸入資料被傳遞給層,然後層對資料進行前向傳遞和設定。最後,結果被傳遞給下一個層。

神經網路層的前向和後向傳播

在神經網路中,層(Layer)是指一組神經元的集合,它們共同處理輸入資料並產生輸出。層的前向傳播(Forward Pass)和後向傳播(Backward Pass)是兩個重要的過程,分別負責計算輸出和更新模型引數。

前向傳播

前向傳播的過程是將輸入資料傳遞給層的每個神經元,然後計算每個神經元的輸出。這個過程可以用以下程式碼表示:

def forward(self, input_):
    self.input_ = input_
    for operation in self.operations:
        input_ = operation.forward(input_)
    self.output = input_
    return self.output

在這段程式碼中,input_是輸入資料,self.operations是層中的一系列操作(Operation),每個操作都有一個forward方法,用於計算輸出。

後向傳播

後向傳播的過程是將輸出誤差(Output Gradient)反向傳遞給層的每個神經元,然後計算每個神經元的梯度。這個過程可以用以下程式碼表示:

def backward(self, output_grad: ndarray) -> ndarray:
    assert_same_shape(self.output, output_grad)
    for operation in reversed(self.operations):
        output_grad = operation.backward(output_grad)
    input_grad = output_grad
    self._param_grads()
    return input_grad

在這段程式碼中,output_grad是輸出誤差,self.operations是層中的一系列操作,每個操作都有一個backward方法,用於計算梯度。

引數梯度

引數梯度(Parameter Gradient)是指模型引數的梯度,它們用於更新模型引數。可以用以下程式碼計算引數梯度:

def _param_grads(self) -> ndarray:
    self.param_grads = []
    for operation in self.operations:
        if issubclass(operation.__class__, ParamOperation):
            self.param_grads.append(operation.param_grad)

在這段程式碼中,self.param_grads是引數梯度的列表,每個元素都是一個操作的引數梯度。

引數

引數(Parameter)是指模型的可學習引數,可以用以下程式碼取得:

def _params(self) -> ndarray:
    #...

這段程式碼的實作取決於具體的模型架構和引數型別。

圖表翻譯:

以下是神經網路層的前向和後向傳播過程的Mermaid圖表:

  graph LR
    A[輸入] -->|forward|> B[層]
    B -->|output|> C[輸出]
    C -->|backward|> D[層]
    D -->|input_grad|> E[輸入]
    E -->|param_grads|> F[引數梯度]
    F -->|params|> G[引數]

這個圖表展示了前向傳播和後向傳播之間的關係,以及引數梯度和引數之間的關係。

全連線層(Dense Layer)

全連線層是一種神經網路層,其中每個輸出神經元都是所有輸入神經元的函式。這種層的特點是,每個輸出都與所有輸入相關,因此也被稱為「密集連線層」或「全連線層」。

全連線層的實作

要實作全連線層,我們需要定義一個類別 Dense,它繼承自 Layer 類別。這個類別需要有以下屬性和方法:

  • __init__ 方法:用於初始化全連線層,需要指定神經元的數量和啟用函式。
  • _setup_layer 方法:用於定義全連線層的操作,包括權重乘法、偏差加法和啟用函式。

實作細節

以下是全連線層的實作細節:

class Dense(Layer):
    def __init__(self, neurons: int, activation: Operation = Sigmoid()) -> None:
        """
        初始化全連線層。

        :param neurons: 神經元的數量
        :param activation: 啟用函式
        """
        super().__init__(neurons)
        self.activation = activation

    def _setup_layer(self, input_: ndarray) -> None:
        """
        定義全連線層的操作。

        :param input_: 輸入資料
        """
        if self.seed:
            # 初始化權重和偏差
            self.weights = np.random.rand(input_.shape[1], self.neurons)
            self.bias = np.zeros((1, self.neurons))

        # 定義操作
        self.operations = [
            WeightMultiply(self.weights),
            BiasAdd(self.bias),
            self.activation
        ]

啟用函式

啟用函式是全連線層的一部分,用於引入非線性因素,使神經網路能夠學習和表示更複雜的關係。常用的啟用函式包括 sigmoid、ReLU、tanh 等。

應用

全連線層是神經網路中最常用的層之一,廣泛應用於各種機器學習任務中,例如影像分類別、語言模型、生成對抗網路等。

圖表翻譯:

  graph LR
    A[輸入資料] --> B[權重乘法]
    B --> C[偏差加法]
    C --> D[啟用函式]
    D --> E[輸出]

內容解密:

以上程式碼定義了一個全連線層,包括初始化、權重和偏差的初始化、操作的定義等。其中,_setup_layer 方法定義了全連線層的操作,包括權重乘法、偏差加法和啟用函式。這些操作是全連線層的核心,用於計算輸出值。

神經網路與損失函式

在深度學習中,神經網路(Neural Network)是一種由多層神經元組成的模型,用於對輸入資料進行預測或分類別。每一層神經元都會對輸入資料進行變換,然後將結果傳遞給下一層神經元。

神經網路的結構

一個基本的神經網路通常包括以下幾個部分:

  1. 輸入層(Input Layer):負責接收輸入資料。
  2. 隱藏層(Hidden Layer):負責對輸入資料進行變換和提取特徵。
  3. 輸出層(Output Layer):負責產生最終的預測結果。

每一層神經元都會對輸入資料進行線性變換和啟用函式的應用,以產生下一層的輸入資料。

損失函式

損失函式(Loss Function)是一種用於衡量模型預測結果與真實結果之間差異的函式。常見的損失函式包括均方差(Mean Squared Error, MSE)和交叉熵(Cross-Entropy)。

反向傳播

反向傳播(Backpropagation)是一種用於訓練神經網路的演算法。它的基本思想是透過計算損失函式對每一層神經元的輸出之間的偏導數,來更新每一層神經元的引數,以最小化損失函式。

實作神經網路

以下是使用 Python 和 NumPy 實作的一個簡單的神經網路:

import numpy as np

class NeuralNetwork:
    def __init__(self, input_size, hidden_size, output_size):
        self.input_size = input_size
        self.hidden_size = hidden_size
        self.output_size = output_size
        self.weights1 = np.random.randn(input_size, hidden_size)
        self.weights2 = np.random.randn(hidden_size, output_size)
        self.bias1 = np.zeros((1, hidden_size))
        self.bias2 = np.zeros((1, output_size))

    def forward(self, x):
        # 輸入層
        hidden_layer = np.dot(x, self.weights1) + self.bias1
        hidden_layer = np.tanh(hidden_layer)
        # 輸出層
        output_layer = np.dot(hidden_layer, self.weights2) + self.bias2
        return output_layer

    def backward(self, x, y, output):
        # 計算損失函式
        loss = np.mean((output - y) ** 2)
        # 計算反向傳播
        d_output = 2 * (output - y)
        d_hidden_layer = np.dot(d_output, self.weights2.T)
        d_weights2 = np.dot(self.hidden_layer.T, d_output)
        d_bias2 = np.sum(d_output, axis=0, keepdims=True)
        d_weights1 = np.dot(x.T, d_hidden_layer)
        d_bias1 = np.sum(d_hidden_layer, axis=0, keepdims=True)
        return d_weights1, d_bias1, d_weights2, d_bias2

    def update(self, d_weights1, d_bias1, d_weights2, d_bias2):
        self.weights1 -= 0.01 * d_weights1
        self.bias1 -= 0.01 * d_bias1
        self.weights2 -= 0.01 * d_weights2
        self.bias2 -= 0.01 * d_bias2

# 測試
nn = NeuralNetwork(2, 2, 1)
x = np.array([[0, 0], [0, 1], [1, 0], [1, 1]])
y = np.array([[0], [1], [1], [0]])
for i in range(1000):
    output = nn.forward(x)
    d_weights1, d_bias1, d_weights2, d_bias2 = nn.backward(x, y, output)
    nn.update(d_weights1, d_bias1, d_weights2, d_bias2)
print(nn.forward(x))

這個實作包括一個簡單的神經網路,有兩個輸入神經元、兩個隱藏神經元和一個輸出神經元。損失函式使用均方差,反向傳播使用梯度下降法更新引數。

神經網路損失函式

在深度學習中,損失函式(Loss Function)扮演著至關重要的角色,它用於衡量模型預測值與真實值之間的差異。下面,我們將實作一個基本的損失函式類別,並探討其成員方法的實作細節。

損失函式類別

import numpy as np

class Loss:
    def __init__(self):
        # 初始化損失函式,目前不進行任何操作
        pass

    def forward(self, prediction: np.ndarray, target: np.ndarray) -> float:
        """
        計算損失值。

        Args:
        - prediction (np.ndarray): 模型預測值。
        - target (np.ndarray): 真實值。

        Returns:
        - loss_value (float): 損失值。
        """
        # 確保預測值和真實值的形狀相同
        assert_same_shape(prediction, target)

        # 儲存預測值和真實值
        self.prediction = prediction
        self.target = target

        # 計算損失值
        loss_value = self._output()
        return loss_value

    def backward(self) -> np.ndarray:
        """
        計算損失函式對輸入的梯度。

        Returns:
        - input_grad (np.ndarray): 輸入的梯度。
        """
        # 計算輸入的梯度
        self.input_grad = self._input_grad()
        
        # 確保預測值和梯度的形狀相同
        assert_same_shape(self.prediction, self.input_grad)
        
        return self.input_grad

    def _output(self) -> float:
        """
        這是一個抽象方法,必須由子類別實作。
        它應該計算並傳回損失值。
        """
        raise NotImplementedError("子類別必須實作_output方法")

    def _input_grad(self) -> np.ndarray:
        """
        這是一個抽象方法,必須由子類別實作。
        它應該計算並傳回輸入的梯度。
        """
        raise NotImplementedError("子類別必須實作_input_grad方法")

內容解密

  • forward 方法用於計算損失值。它首先確保預測值和真實值的形狀相同,然後計算損失值,並傳回這個值。
  • backward 方法用於計算損失函式對輸入的梯度。它計算輸入的梯度,並確保預測值和梯度的形狀相同,然後傳回這個梯度。
  • _output_input_grad 方法是抽象方法,必須由子類別實作。它們分別用於計算損失值和輸入的梯度。

圖表翻譯

  flowchart TD
    A[開始] --> B[計算損失值]
    B --> C[計算梯度]
    C --> D[傳回結果]

圖表翻譯

這個流程圖描述了損失函式的運作過程。首先,計算損失值,然後計算梯度,最後傳回結果。這個過程是深度學習中最佳化模型引數的關鍵步驟。

基礎深度學習

3.1 深度學習基礎

深度學習是機器學習的一個分支,主要使用神經網路來進行模式識別和預測。下面我們將介紹深度學習的基礎知識。

3.2 損失函式

損失函式(Loss Function)是用於衡量模型預測結果與實際結果之間差異的函式。常用的損失函式包括均方誤差(Mean Squared Error, MSE)和交叉熵(Cross-Entropy)。

import numpy as np

class Loss:
    def __init__(self):
        pass

    def _input_grad(self) -> np.ndarray:
        '''
        此方法必須由 Loss 的子類別實作。
        '''
        raise NotImplementedError()

class MeanSquaredError(Loss):
    def __init__(self):
        super().__init__()

    def _output(self) -> float:
        '''
        計算均方誤差。
        '''
        loss = np.sum(np.power(self.prediction - self.target, 2)) / self.prediction.shape[0]
        return loss

    def _input_grad(self) -> np.ndarray:
        '''
        計算均方誤差對輸入的梯度。
        '''
        # 根據均方誤差的公式,對輸入進行梯度計算
        grad = 2 * (self.prediction - self.target) / self.prediction.shape[0]
        return grad

3.3 啟用函式

啟用函式(Activation Function)是用於引入非線性因素的函式,常用的啟用函式包括 Sigmoid、ReLU 和 Tanh。

圖表翻譯:

  graph LR
    A[輸入] --> B[啟用函式]
    B --> C[輸出]
    C --> D[損失函式]
    D --> E[梯度計算]
    E --> F[最佳化]

內容解密:

在上述程式碼中,我們定義了一個 Loss 類別,該類別包含 _input_grad 方法,該方法必須由其子類別實作。在 MeanSquaredError 類別中,我們實作了 _output 方法,該方法計算均方誤差,並實作了 _input_grad 方法,該方法計算均方誤差對輸入的梯度。

在圖表中,我們展示了神經網路的流程,從輸入開始,經過啟用函式、輸出、損失函式、梯度計算和最佳化等步驟。

未來,深度學習將繼續在各個領域中發揮重要作用,包括電腦視覺、自然語言處理和語音識別等。在這些領域中,深度學習可以幫助我們解決更多複雜的問題,並取得更好的成績。

神經網路的實作

在深度學習中,神經網路是一個基本的構建塊。它由多個層組成,每個層都有一個前向傳播和反向傳播的方法。這些方法分別用於計算輸出和計算梯度。

從技術架構視角來看,本文逐步建構了一個基礎神經網路的 Python 實作,涵蓋了核心元件如 Sigmoid 啟用函式、層級設計、前向與反向傳播,以及損失函式的定義和應用。透過程式碼示例,清晰地展現了層級化的設計模式如何組織神經網路的運算流程,並利用 numpy 進行高效的數值計算。分析程式碼可以發現,此實作的重點在於闡述神經網路運作的基本原理,並未針對效能進行深度最佳化,例如 GPU 加速或更複雜的網路結構。其限制在於缺乏實際資料集的訓練與驗證,難以評估模型的泛化能力。對於初學者而言,此簡化的模型有助於理解神經網路的核心概念,但要應用於實際專案,仍需考量資料預處理、模型調參、效能評估等環節。玄貓認為,此程式碼框架提供了一個良好的學習基礎,開發者可以以此為起點,逐步探索更進階的神經網路架構和訓練技巧。未來可以預見,隨著深度學習框架的持續發展,更高階的 API 將進一步簡化神經網路的建構和訓練流程,降低開發門檻,並促進更多創新應用。