>> ต่อจาก
บทที่ ๔ ออปทิไมเซอร์ใน pytorch ออปทิไมเซอร์คืออุปกรณ์สำหรับช่วยในการปรับพารามิเตอร์ด้วยวิธีการเคลื่อนลงตามความชัน
ใน pytorch ได้เตรียมออปทิไมเซอร์ชนิดต่างๆไว้ในมอดูลย่อย torch.optim
ในบทที่ผ่านมาเป็นการใช้วิธีการเคลื่อนลงตามความชันธรรมดาโดยการเขียนเองโดยไม่ได้ใช้ออปทิไมเซอร์ช่วย
เมื่อใช้ออปทิไมเซอร์จะทำให้การเขียนดูเรียบง่ายลง อีกทั้งยังสามารถใช้วิธีที่เหนือกว่าแค่การเคลื่อนลงตามความชันธรรมดา เช่น Adagrad หรือ Adam ได้ง่ายๆ
เกี่ยวกับออปทิไมเซอร์ชนิดต่างๆอ่านรายละเอียดได้ใน
https://phyblas.hinaboshi.com/20171002 ออปทิไมเซอร์ที่เตรียมไว้ใน pytorch ได้แก่
- torch.optim.SGD
- torch.optim.Adam
- torch.optim.Adamax
- torch.optim.Adadelta
- torch.optim.Adagrad
- torch.optim.Rprop
- torch.optim.RMSprop
SGD ก็คือวิธีแบบดั้งเดิมที่แค่คำนวณอนุพันธ์แล้วใช้ปรับค่าเลยโดยตรง
ส่วนวิธีการที่มักถูกแนะนำให้ใช้มากที่สุดคือ Adam ในที่นี้ก็จะใช้วิธีนี้เป็นหลักด้วย
การใช้ออปทิไมเซอร์ ขอยกตัวอย่างการนำออปทิไมเซอร์มาใช้ในการปรับพารามิเตอร์ใน pytorch
ตัวอย่างขอใช้เป็นการวิเคราะห์การถดถอยเชิงเส้นสองตัวแปรเช่นเดียวกับในบทที่แล้ว เขียนโดยใช้ออปทิไมเซอร์ได้ดังนี้
import numpy as np
import matplotlib.pyplot as plt
from mpl_toolkits.mplot3d import Axes3D
import torch
X = np.random.uniform(-2,2,[300,2])
x,y = X.T
z = x*0.7+y*1.5 + np.random.normal(1,0.4,300)
lin = torch.nn.Linear(2,1)
X = torch.Tensor(X)
z = torch.Tensor(z)
eta = 0.05
ha_mse = torch.nn.MSELoss()
opt = torch.optim.Adam(lin.parameters(),lr=eta) # สร้างออปทิไมเซอร์
n_thamsam = 100
for i in range(n_thamsam):
h = lin(X).flatten()
J = ha_mse(h,z)
J.backward()
opt.step() # ปรับพารามิเตอร์
opt.zero_grad() # ล้างอนุพันธ์
mx,my = np.meshgrid(np.linspace(-2,2,11),np.linspace(-2,2,11))
mX = torch.Tensor(np.array([mx.ravel(),my.ravel()]).T)
mz = lin(mX).data.numpy().reshape(11,11)
plt.figure(figsize=[6,6])
ax = plt.axes([0,0,1,1],projection='3d')
ax.scatter(x,y,z,c=z,edgecolor='k',cmap='coolwarm')
ax.plot_surface(mx,my,mz,color='g',rstride=1,cstride=1,alpha=0.1,edgecolor='k')
plt.show()
สิ่งที่เปลี่ยนแปลงจากคราวก่อนก็คือ มีการสร้างออปทิไมเซอร์ขึ้น แล้วส่งพารามิเตอร์เข้าไปให้ออปทิไมเซอร์บันทึกไว้ว่าตัวนี้คือพารามิเตอร์ที่ต้องการปรับค่า ส่วนอัตราการเรียนรู้ก็กำหนดโดยคีย์เวิร์ด lr ก็ป้อนเข้าไปด้วย
นอกจากนี้ค่าตัวเลือกอื่นๆตามชนิดของออปทิไมเซอร์ ก็สามารถกำหนดค่าตรงนี้ด้วย เช่นกรณีของ Adam จะมีค่า β1,β2 ซึ่งกำหนดโดยใส่คีย์เวิร์ด betas โดยใส่พร้อมกันทั้ง ๒ ตัว เป็น betas=(β
1,β
2) กรณีที่ไม่ใส่ก็จะเป็นค่ามาตรฐานตั้งต้น คือ betas=(0.9,0.999)
จากนั้นในระหว่างวนซ้ำ จะใช้คำสั่ง .step() เพื่อทำการปรับค่าพารามิเตอร์ทั้งหมดตามความชันที่คำนวณได้หลังจาก .backward() ไป
สุดท้ายก็สั่ง .zero_grad() เพื่อล้างอนุพันธ์ทั้งหมดที่หามาในรอบนั้นให้เป็น 0 ก่อนที่จะคำนวณรอบถัดไป
ในการใช้งาน pytorch โดยทั่วไปก็จะใช้ออปทิไมเซอร์ในลักษณะนี้ตลอด เป็นขั้นตอนที่ค่อนข้างตายตัว (วิธีที่ผ่านมาในบทก่อนๆแค่เพื่ออธิบายหลักการที่อยู่เบื้องหลัง เพื่อความเข้าใจ)
.zero_grad() นี้บางคนก็วางไว้ก่อน .backward() ผลที่ได้ก็เหมือนกัน ที่สำคัญคือก่อนจะ backward รอบใหม่ต้องมี zero_grad ก่อน
ดูข้อมูลของตัวออปทิไมเซอร์ ถ้าสั่ง print ตัวออปทิไมเซอร์ ข้อมูลของตัวออปทิไมเซอร์นั้นจะแสดงออกมา
lin = torch.nn.Linear(3,1)
opt = torch.optim.Adam(lin.parameters())
print(opt)
ได้
Adam (
Parameter Group 0
amsgrad: False
betas: (0.9, 0.999)
capturable: False
eps: 1e-08
foreach: None
lr: 0.001
maximize: False
weight_decay: 0
)
หากต้องการดูว่าพารามิเตอร์ที่ออปทิไมเซอร์ตัวนั้นดูแลอยู่มีอะไรบางให้ดูที่แอตทริบิวต์ .param_groups
print(opt.param_groups)
ได้
[{'params': [Parameter containing:
tensor([[-0.2683, -0.5022, 0.0204]], requires_grad=True), Parameter containing:
tensor([0.2068], requires_grad=True)], 'lr': 0.001, 'betas': (0.9, 0.999), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False, 'maximize': False, 'foreach': None, 'capturable': False}]
การทำให้พารามิเตอร์บางตัวไม่ปรับค่า พารามิเตอร์โดยทั่วไปจะมีการคำนวณและบันทึกค่าอนุพันธ์เสมอ นั่นคือเป็นเทนเซอร์ที่ถูกตั้ง requires_grad=True
แต่เราสามารถตั้ง requires_grad=False ได้ ซึ่งจะทำให้พารามิเตอร์ตัวนั้นไม่มีการคำนวณอนุพันธ์ และต่อให้ถูกส่งให้ออปทิไมเซอร์ก็จะไม่มีการเปลี่ยนแปลงค่า
lin = torch.nn.Linear(2,2)
lin.weight.requires_grad = False
lin.bias.requires_grad = False
>> อ่านต่อ
บทที่ ๖