# 深度學習與光電應用 HW1 contributed by <[`tintinjian12999`](https://github.com/tintinjian12999)> ## 題目一:以下Python code 分別能產生21筆(x, y)資料,請以PyTorch架構建立給定x值以預測y值的神經網路(2層FC層, 第一層的神經元分別為2, 5, 12),並比較y的預測值與標籤值(將他們畫在同一張圖上) ```python import numpy as np import matplotlib.pyplot as plt x=np.arange(0,10.5,0.5) y=3.5*x*x-3*np.random.randn(len(x))*x+7.6+4*np.random.randn(len(x)); plt.scatter(x,y) ``` 執行結果如下 ![](https://i.imgur.com/LpzZy0W.png) 接下來使用 PyTorch 進行實作 首先使用上面的 code 產生資料並轉換為 pyTorch 使用的 tensor 型態 ```python import numpy as np import matplotlib.pyplot as plt import torch import torch.nn as nn x=np.arange(0,10.5,0.5) y=3.5*x*x-3*np.random.randn(len(x))*x+7.6+4*np.random.randn(len(x)) x = x.tolist() y = y.tolist() t_c = torch.tensor(x).unsqueeze(1) t_u = torch.tensor(y).unsqueeze(1) ``` 轉換為list是為了避免型態是 array 產生的錯誤 ``` tensor([[ 0.0000], [ 0.5000], [ 1.0000], [ 1.5000], [ 2.0000], [ 2.5000], [ 3.0000], [ 3.5000], [ 4.0000], [ 4.5000], [ 5.0000], [ 5.5000], [ 6.0000], [ 6.5000], [ 7.0000], [ 7.5000], [ 8.0000], [ 8.5000], [ 9.0000], [ 9.5000], [10.0000]], dtype=torch.float64) ``` 可以看到若 x 的資料型態為 array 的話在轉換為 tensor 的時候最後會多一項儲存資料型態的元素。 > 後來發現是因為數值儲存的型態為 64 bytes 的浮點數產生的問題,而 pytorch 能接受的為 32 bytes 的浮點數。 > 接著利用 python 提供的亂數 rand 用於產生訓練資料集和驗證資料集的 index ```python n_samples = t_u.shape[0] n_val = int(0.2 * n_samples) shuffled_indices = torch.randperm(n_samples) train_indices = shuffled_indices[:-n_val] val_indices = shuffled_indices[-n_val:] train_indices, val_indices ``` 執行結果如下 ``` (tensor([ 7, 2, 18, 8, 10, 3, 20, 6, 15, 11, 5, 0, 19, 14, 16, 12, 4]), tensor([ 9, 13, 1, 17])) ``` 產生訓練資料集與驗證資料集並進行正規化 ```python t_u_train = t_u[train_indices] #訓練資料集 t_c_train = t_c[train_indices] t_u_val = t_u[val_indices] #驗證資料集 t_c_val = t_c[val_indices] t_un_train = 0.1 * t_u_train #進行正規化 t_un_val = 0.1 * t_u_val ``` 定義要使用的 Nural Network (這裡以2個神經元,共三層為例) ```python seq_model = nn.Sequential(nn.Linear(1, 2), nn.Tanh(), nn.Linear(2, 1)) ``` 定義訓練流程 ```python def training_loop(n_epochs, optimizer, model, loss_fn, t_u_train, t_u_val, t_c_train, t_c_val): for epoch in range(1, n_epochs + 1): t_p_train = model(t_u_train) #將訓練資料輸入模型 loss_train = loss_fn(t_p_train, t_c_train) #計算訓練損失 t_p_val = model(t_u_val) #將驗證資料輸入模型 loss_val = loss_fn(t_p_val, t_c_val)#計算驗證損失 optimizer.zero_grad() loss_train.backward() optimizer.step() if epoch == 1 or epoch % 1000 == 0: print(f"Epoch {epoch}, Training loss {loss_train.item():.4f}," #印出訓練損失及驗證損失 f" Validation loss {loss_val.item():.4f}") ``` 進行訓練 ```python optimizer = torch.optim.SGD(seq_model.parameters(), lr=1e-4) #這裡為了讓結果更穩定,稍微將學習率調低了一點 training_loop( n_epochs = 20000, optimizer = optimizer, model = seq_model, loss_fn = nn.MSELoss(), t_u_train = t_un_train, t_u_val = t_un_val, t_c_train = t_c_train, t_c_val = t_c_val) ``` 最後印出結果 ```python from matplotlib import pyplot as plt t_range = torch.arange(0., 400.).unsqueeze(1) fig = plt.figure(dpi=200) plt.xlabel("X") plt.ylabel("Y") plt.plot(t_c.numpy(), t_u.numpy(), 'o') #描繪出真實的資料點 plt.plot(seq_model(0.1 * t_range).detach().numpy(), t_range.numpy(), 'c-') #描繪出圖6.9的曲線 plt.plot(seq_model(0.1 * t_u).detach().numpy(), t_u.numpy(), 'kx') #描繪出預測的資料點 ``` 結果如下圖 ![](https://i.imgur.com/HKTPynw.png) 可以看到在使用 2 個神經元的情況下預測的模型有較大的誤差,接著分別將神經元的數量增加為 5 與 12 。 使用 5 個神經元 ![](https://i.imgur.com/jZNRHej.png) 使用 12 個神經元 ![](https://i.imgur.com/7LeVO7k.png) 比起使用 2 個神經元,使用 5 個與 12 個神經元產生的結果都有明顯的改善。 ## 題目二: 根據以下計算圖,請用Python / Matlab 的自動微分計算y對x的偏微分值 (在x = 4, 12, -8) ![](https://i.imgur.com/NDAM8p0.png) 透過以下python code 即可達成目的 ```python import autograd.numpy as np from autograd import grad, jacobian, elementwise_grad def v(x): return x * x def u(x): return np.exp(v(x)) def y(x): return u(x) * x dy_dx = grad(y) x = 4.0 dy_dx_value = dy_dx(x) print(dy_dx_value) ``` 結果為 ``` 293241647.1767598 (x = 4) ``` ``` 9.98396929791371e+64 (x = 12) ``` ``` 8.043342314246985e+29 (x = -8) ```