ตอนที่ 1 : Gradient Descent คือ(เกือบ)ทุกอย่าง

🏠 Supervised Learning

ในตอนนี้เราจะมาทำความเข้าใจกับ Gradient Descent กันก่อน สำหรับ Linear Regression Model ขอให้ผู้อ่านมองว่า model เป็นกล่องๆหนึ่งที่มีการดำเนินการบ้างอย่างข้างในเมื่อเราใส่ input บางอย่างเพื่อให้ได้ output บางอย่าง

Linear Regression Model (with univariate)

ลำดับการทำงานคร่าวๆเพื่อให้ได้ model มา

TrainingsetLearningAlgorithmModel(f)Training\,set\\ \downarrow \\ Learning\,Algorithm\\ \downarrow \\ Model\,(f)

จาก model ทีได้มาเราก็จะสามารถนำค่า x x ที่อยู่ใน training set หรือไม่อยู่ก็ได้ มาป้อนใส่ model ของเราเพื่อให้ model ทำนายค่า y^\hat{y} ออกมา

xf(model)y^x → f_{(model)} → \hat{y}

แล้ว ff คืออะไรล่ะ?

fw,b(x)=wx+bf_{w,b}(x) = wx+b

ff คือ Linear function ที่มี xx เป็น input ขึ้้นอยู่กับ ww กับ bb และให้ผลลัพธ์เป็น y^\hat{y} หรือที่เรียกกันทั่วไปว่า Linear Regression Model

Model ที่กล่าวไปข้างต้้นเป็นเพียง model สำหรับ 1 ตัวแปลเท่านั้น หรือเรียกว่า Univariate Linear Regression Model (Univariate = one variable)

จาก function ที่ได้กล่าวถึงไปก่อนหน้านี้ สมมติว่าเรามี training set อยู่จำนวนหนึ่ง พล็อตออกมาได้ดังรูป แล้วได้ Linear function เป็น fw,bf _{w,b}

fw,bf _{w,b} จะต้องทำนาย y^\hat{y} จากค่า x(i)x^{(i)} โดยมี target เป็น y(i) y^{(i)}

โดยที่

y^=fw,b(x(i))fw,b(x(i))=wx(i)+b\begin {aligned} \hat{y} = f _{w,b}(x^{(i)})\\ f _{w,b}(x^{(i)}) = wx^{(i)}+b \end {aligned}

แล้วเราจะหาค่า w,bw, b ที่เหมาะสมได้อย่างไรล่ะ? แต่ก่อนจะไปถึงขั้นนั้นเรามาทำความรู้จักกับ Cost Function กันก่อน

Cost Function

จาก Linear function fw,bf _{w,b} ที่เราได้มามันสามารถ fit กับข้อมูลที่เรามีอยู่ได้ขนาดไหน เราจะสามารถทราบได้โดยการวัด Error โดยใช้ cost function การวัด Error ที่มักนิยมใช้กับ Linear Regression คือ Squared Error

💡
จริงๆแล้ว cost function มีมากมายหลายแบบโดยจะเลือกใช้ตามลักษณะงานหรือโจทย์ปัญหา
J(w,b)=12mi=1m(y^(i)y(i))2J(w,b)=12mi=1m(fw,b(x(i))y(i))2\begin{aligned} J_{(w,b)}&=\frac{1}{2m}\sum_{i=1} ^{m}(\hat{y}^{(i)}-y^{(i)})^2\\ J_{(w,b)}&=\frac{1}{2m}\sum_{i=1} ^{m}(f_{w,b}(x^{(i)}) -y^{(i)})^2\\ \end{aligned}

แล้ว Cost Function มันเกี่ยวอะไรกับการหา w,bw,b ?

จากที่ได้กล่าวไปข้างต้นจะสังเกตได้ว่า ความ fit ของ model กับชุดข้อมูล แปลผกผันกับ ค่าของ cost function ดังนั้นถ้าหากว่าเราต้องการให้ model ของเรา fit กับชุดข้อมูลมากเราก็ยิ่งต้องทำให้ cost function ของเรามีค่าน้อยเท่านั้น จะได้ว่า

minimizew,bJ(w,b)\underset{w,b}{minimize} J(w,b)

ตัวอย่าง

ในตัวอย่างนี้จะเป็นตัวอย่างแบบง่ายโดยจะให้สนใจแค่ ww จึงกำหนด bb  เป็น 0

ให้ x={1,2,3},y={1,2,3},w=1,b=0x = \{1,2,3\} , y=\{1,2,3\}, w= 1 ,b=0

จะได้ว่า 

f(x)=wxJ(w)=12mi=1mfw(x(i)y(i))2J(w)=12mi=1m(wx(i)y(i))2\begin{aligned} f(x)&=wx\\ J(w) &= \frac{1}{2m} \sum ^m _{i=1} f_w(x^{(i)}-y^{(i)})^2 \\ J(w) &= \frac{1}{2m} \sum ^m _{i=1}(wx^{(i)}-y^{(i)})^2 \\ \end{aligned}
J(1)=16(02+02+02)J(1)=0\begin{aligned} J(1) &= \frac{1}{6}(0^2+0^2+0^2) \\ J(1) &= 0 \end{aligned}

จากโมเดลของเราถ้าให้ w=0w = 0 จะทำให้ได้ค่า cost function ต่ำสุด

ถ้าหากเราลองเปลี่ยนค่า w ให้เป็นค่าอื่นก็จะได้ค่า cost function ที่ต่างกันออกไป

ให้ w=10w = 10 จะได้ cost function = 189

ให้ w=9w = -9 จะได้ cost function = 233

ดังนั้นค่า ww ที่เหมาะสมที่จุดคือ w=1 w = 1

แล้วเราต้องมาสุ่มค่า ww เพื่อให้ได้ค่า cost function ต่ำสุดหรอ? แล้วกรณีที่ค่าต่ำสุดไม่ใช่ 00 ล่ะเราจะรู้ได้อย่างไรว่าค่าที่เราได้นั้นต่ำสุดแล้ว? แล้วถ้า bb ของ model เราไม่ได้เป็น 00 อีกล่ะ ต่อไปเราจะมาทำความรู้จักกับ Gradient Descent กัน

ภาพตัวอย่างกราฟในกรณีที่ไม่ได้กำหนด b=0b=0

Gradient Descent

คอนเซปของคร่าวๆของ Gradient Descent คือ สมมติว่าเรามี Cost Funciton J(w,b)J(w,b) ให้เป็น Cost Function ของ Non-Linear Regression(ซึ่งเราจะกล่าวถึงในอนาคต) โดยเปรียบเทียบ J(w,b)J(w,b) เป็นเหมือนกับทุ่งหญ้ากว้างที่มีทั้งเนินสูงและต่ำ โดย w,bw,b เป็นตำแหน่งที่เราอยู่ เรามีหน้าที่คือต้องเดินไปยังจุดที่ต่ำที่สุดในทุ่งหญ้ากว้างนี้โดยไปทีละก้าว สิ่งที่เราต้องทำคือ

  1. มองไปรอบๆตัวเพื่อที่จะหาจุดที่ต่ำกว่าจุดที่เรายืนอยู่ตอนนี้
  1. เมื่อเจอแล้วให้ก้าวไปที่จุดนั้น
  1. จากนั้นกลับไปทำข้อที่หนึ่งเรื่อยๆจนกว่าจะมองหาจุดที่ต่ำกว่าจุดที่เรายืนไม่ได้แล้ว
  1. เรามาถึงจุดที่ต่ำที่สุดแล้ว

ถึงแม้ว่าคอนเซปจะเข้าใจง่าย(หรือป่าวนะ?)แต่การที่จะ implement ไม่ได้ง่ายอย่างที่คิด

ภาพทุ่งหญ้าที่มีเนินสูงต่ำ

คำอธิบายภาพ : ลูกศรและกากบาทสีดำเปรียบเสมือนขั้นตอนที่ 1-3 ในบางครั้งเราอาจจะคิดว่าเราอยู่จุดที่ต่ำสุดแล้ว(เส้นทางเดินที่ 2) แต่จริงๆแล้วมีจุดที่ต่ำกว่าจุดที่เราอยู่แต่เรามองไม่เห็น(เส้นทางเดินที่ 1)

Implementation

💡
Implementation นี้ผู้เขียนขอกำหนดให้เครื่องหมาย ==  เป็นการกำหนดค่า(Assignment) เช่น a = 1 หมายความว่า a มีค่าเท่ากับ 1 ไม่ใช่ เครื่องหมายที่เท่ากับที่มีความหมายทางคณิตศาสตร์ที่แสดงว่าค่าฝั่งซ้ายของเครื่องหมายมีค่าเท่ากับค่าของฝั่งขวาของเครื่องหมาย(Truth Assertion)
💡
Implementation นี้เป็นการ implement ในขั้นตอนที่ 1 และ 2 จากทีเคยกล่าวไปข้างต้น
wnew=woldαwJ(w,b)bnew=boldαbJ(w,b)\begin{aligned} w_{new} &= w_{old}-\alpha \frac{\partial}{\partial w}J(w,b) \\ b_{new} &= b_{old}-\alpha \frac{\partial}{\partial b}J(w,b) \end{aligned}

โดย

การกำหนดขนาดของ Learning Rate (α\alpha :ขนาดของการก้าว)ควรกำหนดในขนาดที่เหมาะสมเพราะจะมีโอกาสเกิดเหตุการณ์เหลานี้(จะกล่าวถึงวิธีการเลือกในอนาคต)

วิธีการป้องกันไม่ให้ก้าวเลยจุดที่มีค่าต่ำสุดคือการปรับ Learning Rate แบบ Dynamic โดยให้เริ่มต้นมี α\alpha ค่ามากก่อนและเมื่อ derivative ของ Cost Function มีขนาดเล็กลงก็ค่อยๆลดค่าของ α\alpha ลง

หรือไม่ก็ทดลอง α\alpha มีค่าต่างๆเช่น ลองจาก 0.001, 0.01, 0.1, 1 แล้วลองพล็อตกราฟ Cost Function ต่อ iteration ออกมาเปรียบเทียบกัน(จะกล่าวถึงในอนาคต)

α\alpha มีค่าน้อยเกินไป

α\alpha มีค่ามากเกินไป
ปรับค่า α\alpha แบบ dynamic

Assemble

ทีนี้เรามาเริ่มใช้ทุกอย่างที่เรากล่าวถึงไปก่อนหน้านี้กัน

กำหนดให้

Linear Regression Model :

fw,b(x)=wx+bf_{w,b}(x) = wx+b

Cost Function :

J(w,b)=12mi=1m(fw,b(x(i))y(i))2J(w,b) = \frac{1}{2m} \sum _{i=1} ^{m} (f_{w,b}(x^{(i)})-y^{(i)})^2

Gradient Descent Algorithm :

💡
เครื่องหมาย == ของ Gradient Descent Algorithm หมายถึงการ assignment
Repeatuntilconvergence{wnew=woldαwJ(w,b)bnew=boldαbJ(w,b)}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{new} = w_{old}-\alpha \frac{\partial}{\partial w}J(w,b) \\ &b_{new} = b_{old}-\alpha \frac{\partial}{\partial b}J(w,b)\\ &\} \end{aligned}

เริ่มจากส่วนของ Partial Derivative ใน Gradient Descent Algorithm ก่อน

เอา cost function และ model ของเรามาแทนในพจน์ Partial Derivative

Weight :

wJ(w,b)=ddw12mi=1m(fw,b(x(i))y(i))2=ddw12mi=1m(wx(i)+by(i))2usechainrule;=12mi=1md(wx(i)+by(i))2d(wx(i)+by(i))d(wx(i)+by(i))dw=12mi=1m2(wx(i)+by(i))x(i)=1mi=1m(wx(i)+by(i))x(i)\begin{aligned} \frac{\partial}{\partial w}J(w,b)&= \frac{d}{dw} \frac{1}{2m}\sum_{i=1}^m(f_{w,b}(x^{(i)})-y^{(i)})^2\\ &=\frac{d}{dw} \frac{1}{2m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})^2\\ use\,chain\,rule\,;\\ &=\frac{1}{2m}\sum_{i=1}^m \frac{d(wx^{(i)}+b-y^{(i)})^2}{d(wx^{(i)}+b-y^{(i)})}\frac{d(wx^{(i)}+b-y^{(i)})}{dw}\\ &=\frac{1}{2m}\sum_{i=1}^m2(wx^{(i)}+b-y^{(i)})x^{(i)}\\ &=\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})x^{(i)}\\ \end{aligned}

Bias :

bJ(w,b)=ddb12mi=1m(fw,b(x(i))y(i))2=ddb12mi=1m(wx(i)+by(i))2usechainrule;=12mi=1md(wx(i)+by(i))2d(wx(i)+by(i))d(wx(i)+by(i))db=12mi=1m2(wx(i)+by(i))=1mi=1m(wx(i)+by(i))\begin{aligned} \frac{\partial}{\partial b}J(w,b)&= \frac{d}{db} \frac{1}{2m}\sum_{i=1}^m(f_{w,b}(x^{(i)})-y^{(i)})^2\\ &=\frac{d}{db} \frac{1}{2m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})^2\\ use\,chain\,rule\,;\\ &=\frac{1}{2m}\sum_{i=1}^m \frac{d(wx^{(i)}+b-y^{(i)})^2}{d(wx^{(i)}+b-y^{(i)})}\frac{d(wx^{(i)}+b-y^{(i)})}{db}\\ &=\frac{1}{2m}\sum_{i=1}^m2(wx^{(i)}+b-y^{(i)})\\ &=\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})\\ \end{aligned}

จะได้ Gradient Descent Algorithm ใหม่เป็น

Repeatuntilconvergence{wnew=woldα1mi=1m(wx(i)+by(i))x(i)bnew=boldα1mi=1m(wx(i)+by(i))}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{new} = w_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})x^{(i)}\\ &b_{new} = b_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})\\ &\} \end{aligned}

จาก Gradient Descent Algorithm ที่กล่าวไปว่าให้ทำซ้ำจนกว่าจะ convergence

แล้วตรงไหนถึงเรียกว่า Convergence?

ให้ลองพล็อตค่า Cost Function ของแต่ละ Iteration ใน Gradient Descent ออกมา แล้วสังเกตว่าที่ Iteration ใดที่ Cost Function เริ่มมีการลดลงน้อยกว่าขนาดของ Learning Rate นั้นคือ Gradient Descent กำลัง Convergence

Code Implementation (Python) for Linear Regression (with univariate)

J(w,b)=12mi=1m(fw,b(x(i))y(i))2J(w,b) = \frac{1}{2m} \sum _{i=1} ^{m} (f_{w,b}(x^{(i)})-y^{(i)})^2
def compute_cost(x, y, w, b):
	"""
	Parameters
	* ใน implementation นี้ผู้เขียนขอใช้ x,y เป็น numpy array
		x => data set ที่มีขนาด m ตัว
		y => taget set ที่มีขนาด m ตัว
		w => weight
		b => bias
	return ค่าผลลัพธ์ของ cost (total_cost)
	"""
	m = x.shape[0]
	cost = 0
	
	for i in range(m):
	    f_wb = w * x[i] + b
	    cost = cost + (f_wb - y[i])**2
	total_cost = 1 / (2 * m) * cost
	
	return total_cost
wnew=woldαwJ(w,b)bnew=boldαbJ(w,b)\begin{aligned} w_{new} &= w_{old}-\alpha \frac{\partial}{\partial w}J(w,b) \\ b_{new} &= b_{old}-\alpha \frac{\partial}{\partial b}J(w,b) \end{aligned}
def compute_gradient(x, y, w, b): 
	"""
	Parameters
	* ใน implementation นี้ผู้เขียนขอใช้ x,y เป็น numpy array
		x => data set ที่มีขนาด m ตัว
		y => taget set ที่มีขนาด m ตัว
		w => weight
		b => bias
	Returns
	  dj_dw => derivative ของ dj/dw
	  dj_db => derivative ของ dj/db
	"""
	m = x.shape[0]    
	dj_dw = 0
	dj_db = 0
	
	for i in range(m):  
	    f_wb = w * x[i] + b 
	    dj_dw_i = (f_wb - y[i]) * x[i] 
	    dj_db_i = f_wb - y[i] 
	    dj_db += dj_db_i
	    dj_dw += dj_dw_i 
	dj_dw = dj_dw / m 
	dj_db = dj_db / m 
	    
	return dj_dw, dj_db
Repeatuntilconvergence{wnew=woldα1mi=1m(wx(i)+by(i))x(i)bnew=boldα1mi=1m(wx(i)+by(i))}\begin{aligned} &Repeat\,until\,convergence\{\\ &w_{new} = w_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})x^{(i)}\\ &b_{new} = b_{old}-\alpha\frac{1}{m}\sum_{i=1}^m(wx^{(i)}+b-y^{(i)})\\ &\} \end{aligned}
def gradient_descent(x, y, w_in, b_in, alpha, num_iters, gradient_function): 
	"""
	Parameters
	* ใน implementation นี้ผู้เขียนขอใช้ x,y เป็น numpy array
		x => data set ที่มีขนาด m ตัว
		y => taget set ที่มีขนาด m ตัว
		w_in => initial weight ค่าเริ่มต้นของ weight
		b_in => initial bias ค่าเริ่มต้นของ bias
		alpha => learning rate
		num_iters => จำนวนรอบที่จะทำซ้ำ
		gradient_function => เรียกใช้ function compute_gradient
	Returns
		w => ค่าผลลัพธ์สุดท้ายของ weight
		b => ค่าผลลัพธ์สุดท้ายของ bias
	"""
	b = b_in
	w = w_in
	
	for i in range(num_iters):
		dj_dw, dj_db = gradient_function(x, y, w , b)     

		b = b - alpha * dj_db                            
		w = w - alpha * dj_dw                            
	
	return w, b

จบไปแล้วกับ ตอนที่ 1 : Gradient Descent คือ(เกือบ)ทุกอย่าง ในตอนนี้ได้กล่าวถึง Linear Regression Model (with univariate), Cost Function, Gradient Descent ผู้เขียนต้องการที่จะแสดงให้ผู้อ่านเข้าใจถึงวิธีการเรียนรู้ของเครื่องว่ามันสามารถเรียนรู้ได้อย่างไรผ่านคอนเซปต์ของ Gradient Descent โดยอาจารย์ของผู้เขียนได้เคยกล่าวไว้ว่า “ถ้าหากเข้าใจ Gradient Descent เวลาเดินเท้าจะมีดอกบัวมารอง หัวจะเปล่งแสง ถ้าเข้าใจคอนเซปต์ก็เหมือนจะเข้าใจ Machine Learning เกือบทั้งหมดแล้ว” เลยเป็นที่มาของชื่อตอนนี้ด้วย ทั้งนี้บทความนี้เป็นการสรุปเนื้อหาจากคอร์สออนไลน์ของ DeepLearning.AI และที่อื่นๆ ผู้เขียนเองไม่ได้มีเจตนาในการแสวงหาผลกำไร แต่ต้องการที่จะสรุปเนื้อหาเพื่อเพิ่มความเข้าใจให้กับตัวเองผ่านการใช้คำในแบบของตัวเอง และเพิ่มแหล่งความรู้ที่เป็นภาษาไทยเผื่อผู้ที่มีความสนใจในด้านนี้เหมือนกัน หวังว่าจะได้รับประโยชน์ไม่มากก็น้อยนะครับ นี่เป็นครั้งแรกที่ผมเขียนบทความ อาจจะมีผิดพลาดไปบ้าง อาจจะยังไม่สามารถอธิบายให้เข้าใจได้ง่าย อาจจะเลือกใช้คำผิดไปบ้าง แต่จะพยายามให้มากขึ้นครับ หากบทความมีการใช้คำผิดพลาดหรือผู้เขียนเข้าใจผิดสามารถแจ้งปัญหาได้ที่ https://github.com/Warapob/Learn-MachineLearning/issues

แหล่งอ้างอิง

⏩ ตอนที่ 2 : Features เต็มไปหมด