搭建一個簡單的三層神經網絡


1. 背景

  • 使用numpy庫手動實現一個前向傳播過程
  • 使用pytorch搭建一個簡單的分類網絡,搭配cifar-10數據集,完成的一個簡單物體分類模型的搭建、訓練、預測和評估。

2. 數據集介紹

    cifar-10數據集是圖像分類任務中最為基礎的數據集之一,它由60000張32像素* 32像素的圖片構成,包含10個類別,每個類別有6000張圖片。其中50000張圖片被划分為訓練集,10000張為測試集。
image

3. 相關知識點

  • 前向傳播原理
  • 基礎分類模型搭建、訓練及評估

4. 案例

task1:簡單神經網絡的前向傳播

任務分析

問題1:定義初始參數及激活函數
image

上圖展示的是一個簡單的神經網結構,它由一個輸入層(藍色)、兩個隱藏層(黃色)和一個輸出層(紅色)組成。

  • numpy數組定義
    樣例代碼
import numpy as np
a = np.array([1, 3, 5])
  • tanh激活函數
    tanh激活函數數學計算公式如下:

\[tanh(x) = \frac{e^x - e^{-x}}{e^x + e^{-x}} \]

問題2:逐層計算神經網絡輸出

  1. numpy的點成與矩陣相乘
  • 點乘: numpy.dot()
         一維矩陣:計算內積,即:dot( 1 x n , 1 x n ) = 一個數二維矩陣:線性代數矩陣相乘(n x m)·(m x s),即dot( n x m , m x s ) = n x s
  • 對應元素相乘:Numpy.multiply()和“*”
        multiply( n x m , n x m ) = n x m( n x m ) * ( n x m ) = n x m注:兩個矩陣必須行列相同
  1. 神經網絡的乘法計算
完整步驟

  使用numpy實現神經網絡的前向傳播過程,並算出輸出層的最終輸出結果。為了完成上述任務我們需要進行如下假設:

  1. 輸入的值為[3,5]
  2. 隱藏層h1的兩個權重為[2,4]、[4,-5]
  3. 隱藏層h2的兩個權重為[-1,1]、[2,2]
  4. 輸出層的權重為[-3,7]
  5. 所有層不使用偏置
  6. 所有隱藏層需添加tanh激活函數

定義一個numpy數組,內容為神經網絡的輸入數據

input_data = np.array([3, 5])

# 定義數據,作為輸入數據
input_data = np.array([3, 5])
# 定義各個節點權重
weights = {
    'h11': np.array([2, 4]),
    'h12': np.array([4, -5]),
    'h21': np.array([-1, 1]),
    'h22': np.array([2, 2]),
    'out': np.array([-3, 7])
}

# 定義tanh激活函數
def tanh(x):   
    return (np.exp(x) - np.exp(-x)) / (np.exp(x) + np.exp(-x))

# 輸入層數據與第一隱層權重相乘、求和,並輸入激活函數中
hidden_11_value = tanh( (input_data * weights['h11']).sum() )
hidden_12_value = tanh( (input_data * weights['h12']).sum() )

hidden_1_output = np.array([hidden_11_value, hidden_12_value])

# 第一層輸出數據與第二層隱層權重相乘、求和,並輸入到激活函數
hidden_21_value = tanh( (hidden_1_output * weights['h21']).sum() )
hidden_22_value = tanh( (hidden_1_output * weights['h22']).sum() )
hidden_2_output = np.array([hidden_21_value, hidden_22_value])

# 輸出層,無激活函數
output = (hidden_2_output * weights['out']).sum()print(output)

至此,已完成全部計算。

task2 cifar-10圖像分類

問題1:搭建簡單的神經網絡

在本問題中,nn.Linear的主要參數有in_features和out_features,只需要填入對應的形狀即可,樣例如下:

input_ = torch.randn(128, 20)
layer = nn.Linear(20, 30)
out = layer(input)

問題2:神經網絡的訓練

本問題中,課根據訓練步驟完成代碼,神經網絡訓練步驟如下:

  1. 清空優化器梯度
  2. 讀入data和label
  3. 運行模型前向傳播過程
  4. 基於模型輸出生成最終結果
  5. 計算損失
  6. 基於損失計算梯度
  7. 基於梯度更新參數
    樣例代碼如下
outputs = net(inputs)  # 模型前向傳播
loss.backwards()  # 用於計算梯度
optimizer.step()  # 用於參數更新
optimizer.zero_grad()  # 用於清空優化器梯度
inputs,label = data  # 用於讀取data和label
inputs = inputs.view(-1, 32*32*3)  # 用於對輸入形狀進行變化
preds

問題3:模型測評

模型測評過程中的數據導入、前向傳播過程與訓練過程基本相同。

完整步驟
  1. 大for循環-epochs,用於管理一套數據循環訓練幾遍
  2. 小for循環-step,用於以batchsize為單位,從dataloader中調取數據
  3. 清空優化器的梯度
  4. 讀入data和label,並進行形狀變換(可做可不做)
  5. 運行模型前向傳播過程
  6. 基於模型輸出生成最終結果
  7. 計算損失
  8. 基於損失計算梯度
  9. 基於梯度更新參數
transform = transforms.Compose([

    transforms.ToTensor(),
    transforms.Normalize(
        (0.49140, 0.48216, 0.44653),
        (0.24703, 0.24349, 0.26159) )
])

trainset = torchvision.datasets.CIFAR10(root=r'.', train=True, download=True, transform=transforms)
testset = torchvision.datasets.CIFAR10(root='.', train=False, download=True, transform=transforms)

trainloader = torch.utils.data.DataLoader(trainset, batch_size=16, shuffle=16)
testloader = torch.utils.data.DataLoader(testset, batch_size=16, shuffle=16)

print(trainset.classes)  # 查看類別

# 搭建簡單神經網絡
class Net(nn.Module):
    def __init__(self):
        super(Net, self).__init__()

        self.fc1 = nn.Linear(32*32*3, 1000)
        self.fc2 = nn.Linear(1000, 500)
        self.fc3 = nn.Linear(500, 10)
        
    def forward(self, x):
        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
     
        return self.fc3(x)

net = Net()
# 定義損失函數
criteria = nn.CrossEntropyLoss()

# 定義優化器,將神經網絡參數傳入,並定義學習率
optimizer = optim.Adam(net.parameters(), lr=1e-4)

# 神經網絡訓練
num_epochs = 10
since = time.time()
net.train()
for epoch in range(num_epochs):

    print(f"Epoch {epoch + 1}/{num_epochs}")
    running_loss = 0.0
    running_correct = 0
    for data in tqdm(trainloader):

        # 清空梯度
        optimizer.zero_grad()

        inputs, labels = data
        outputs = net(inputs.view(-1, 32*32*3))

        loss = criteria(outputs, labels)
        loss.backward()

        optimizer.step()

        _, preds = torch.max(outputs, 1)

        running_loss += loss.item() * inputs.size(0)
        running_correct += torch.sum(preds == labels)

    epoch_loss = running_loss / trainloader.dataset.data.shape[0]
    epoch_acc = running_correct.double() / trainloader.dataset.data.shape[0]

    print("train loss: {:.4f} Acc: {:.4f}".format(epoch_loss, epoch_acc))
    print('+++'*10)

time_elapsed = time.time() - since
print('Training complete in "{:0f}m{:.0f}s'.format(time_elapsed // 60, time_elapsed % 60))

# 模型評估
correct, total = 0, 0
net.eval()
for data in tqdm(testloader):    
    inputs, labels = data    
    inputs = inputs.view(-1, 32*32*3)    
    
    outputs = net(inputs)    
    _, predict = torch.max(outputs, 1)    
    
    total += labels.size(0)    
    correct += (predict == labels).sum().item()
    
print("The test set accuracy of network is: %d %%" % (100 * correct / total))


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM