Hidden Skill of Regression Model — ความสามารถลึกลับของโมเดล Regression ที่ไม่เคยบอกใคร



TL;DR ที่จริงแล้ว Regression Model สามารถเรียนรู้ความไม่แน่นอนของข้อมูล (Aleatoric Uncertainty) ได้ โดยใช้การพยากรณ์ Standard Deviation และใช้ค่านี้คำนวณค่า Loss ร่วมกันกับค่าที่พยากรณ์ออกมา (ซึ่งที่จริงแล้วคือว่า Mean) แต่โดยทั่วไปแล้วการ train โมเดลประเภทนี้เราจะไม่สนใจค่าของความไม่แน่นอน ทำให้ loss function ของเราพิจารณาแค่ความผิดพลาดของค่าที่พยากรณ์ออกมา

สวัสดีครับ วันนี้เราจะมาพูดถึงความสามารถหนึ่งของโมเดลประเภท Regression ที่หลายคนอาจจะไม่รู้ หรือหลายคนอาจคิดว่ามันไม่สำคัญ วันนี้ผมจะมาเล่าให้ฟังว่ามันคืออะไร และมีประโยชน์อย่างไรครับ

ก่อนอื่นขอปูพื้นฐาน สำหรับผู้อ่านที่พอจะมีพื้นฐานอยู่แล้วว่าโมเดล Regression คืออะไร อาจจะข้ามส่วนนี้ไป หรืออาจจะอ่านซ้ำเพื่อทดสอบความเข้าใจอีกครั้งก็ได้ครับ

Regression Model คืออะไร ?

Regression Model หรือ โมเดลประเภท Regression คือ โมเดลเพื่อการพยากรณ์ (Predictive Model) ประเภทหนึ่งที่จะพยากรณ์คำตอบที่เป็นเชิงปริมาณให้กับเรา โดยจะพิจารณาจาก input แล้วโมเดลจะพยากรณ์ค่า output ออกมาให้กับเรา

โดยทั่วไปแล้ว การทีเราจะใช้งานโมเดลได้ เราจะต้องทำ 2 ขั้นตอนคือ

  1. Training / Learning / Fitting ทั้งหมดนี้มีความหมายเหมือนกัน คือการให้โมเดลของเราไปเรียนรู้ข้อมูลที่เรามีก่อน ซึ่งอาจเป็นข้อมูลในอดีตที่เกิดขึ้นแล้ว
  2. Inference / Predict คือการนำโมเดลที่เรียนรู้ตามที่เราต้องการแล้ว ไปใช้พยากรณ์กับข้อมูลที่โมเดลไม่เคยพบเจอมาก่อน โดยโมเดลจะใช้ความรู้ที่เรียนมาจากตอน training นั่นเอง

ตัวอย่างของโมเดลแบบ Regression เช่น โมเดลที่จะพยากรณ์เวลาที่ผู้เล่นเกมจะต้องรอในการจับคู่เล่นเกม RoV โดยโมเดลนี้อาจจะนำเอาข้อมูลการรอที่ผ่านมาในอดีตมาให้โมเดลเรียนรู้ โดยนำเอาปัจจัยต่าง ๆ ที่เกี่ยวข้อง เช่น วัน เวลา จำนวนคนในเซิฟเวอร์ เป็นต้น แล้วพยากรณ์ออกมาเป็นเวลาที่คาดว่าผู้เล่นจะต้องรอในการจับคู่เล่นเกม

การเรียนรู้ของโมเดลประกอบด้วยส่วนหลัก ๆ ด้วยกัน 3 ส่วน ได้แก่

  1. ตัวของเน็ตเวิร์ก หรือโมเดลเอง ที่จะคำนวณเอาค่า output ออกมา
  2. Loss function หรือการวัดผลการพยากรณ์ของโมเดล
  3. การปรับโมเดล โดยดูจากการวัดผลว่าผิดไปเท่าไร แล้วปรับโมเดลถูกต้องมากขึ้น

ซึ่งโดยทั่วไปแล้วในการเรียนรู้ของโมเดลโดยใช้ข้อมูลในอดีตที่มีอยู่นั้น ส่วนที่ 1.) เราก็มักจะให้โมเดลคำนวณผลลัพธ์ออกมาเป็นตัวเลขเพียงค่าเดียว ซึ่งก็คือค่าคำตอบของการพยากรณ์ และในส่วนที่ 2.) เราก็จะพิจารณาว่ามันผิดไปจาก training data ที่เราใช้สอนโมเดลมากน้อยแค่ไหน แล้วก็ปรับค่าในโมเดล

ความสามารถอีกอย่างหนึ่งของ Regression Model

ที่จริงแล้ว Regression Model ทำงานอยู่บนพื้นฐานของ Gaussian / Normal Distribution หรือ การแจกแจงแบบปกติ ซึ่งประกอบไปด้วยค่า 2 ค่าที่จะกำหนดลักษณะของการแจกแจงนี้ นั่นก็คือ mean และ standard deviation

หน้าที่ของโมเดล Regression คือการพยากรณ์ค่าของ parameters ที่เหมาะสมของ Gaussian Distribution นั่นหมายความว่า โมเดลจะต้องให้ผลลัพธ์ออกมา 2 ค่า ซึ่งที่คือ mean (μ) กับ std. deviation (σ) ตามที่บอกไว้ก่อนหน้านี้นั่นเอง

ค่าของ std. deviation (σ) หรือ variance (σ²) เป็นค่าที่บอกให้เรารู้ถึงความไม่แน่นอนของผลลัพธ์การพยากรณ์ เช่น สมมุติว่าในกรณีของโมเดลทำนายเวลารอในเกม RoV บอกเราว่าเราจะต้องรอประมาณ 10 วินาที แต่ถ้าโมเดลทำนายส่วนของ std. deviation ให้มีค่าสูง เช่น ให้ค่าเท่ากับ 8 วินาที นั่นแปลว่า ผลลัพธ์ที่ทำนายว่า 10 วินาทีกลายเป็น 10 +- 8 วินาที โดยที่ยิ่งค่าของ σ ยิ่งมีค่าน้อย แปลว่าโมเดลยิ่งมีความมั่นใจกับค่าที่พยากรณ์มาก

และเมื่อโมเดลของเราให้ผลลัพธ์ออกมา 2 ค่าแบบนี้ แน่นอนว่าการคำนวณ loss function ก็ต้องเปลี่ยนไปด้วยเช่นเดียวกันครับ

ที่จริงแล้ว loss function ส่วนใหญ่ที่ใช้กันอยู่ใน deep learning นั้นมีที่มาจาก Negative Log Likelihood ซะส่วนใหญ่ ยกตัวอย่างเช่นในกรณีของ classification เราใช้ loss function ที่มีที่มาจาก Negative Log Likelihood ของ Categorical Distribution ซึ่งในกรณีของ Regression เองก็ใช้ loss function ที่มาจาก Negative Log Likelihood ของการแจกแจงแบบปกติ หรือ Gaussian Distribution นั่นเอง

อะไรคือ Negative Log Likelihood สามารถดูได้จากลิ้งนี้นะครับ https://medium.com/@dopplerz/c68f2722ab91

จะเห็นได้ว่า Negative Log Likelihood นั้นมีบทบาทสำคัญมาก ๆ ในการขับเคลื่อนและพัฒนา Deep Learning Model

Negative Log Likelihood ของ Gaussian Distribution หรือ loss function ที่ต้องใช้ในกรณีนี้ คือ

สังเกตว่า ในกรณีของ Regression โดยทั่วไปนั้น เราพิจารณาแค่เพียงค่าเดียว คือ mean (μ) โดยที่ไม่สนใจค่าของ standard deviation (σ) และเมื่อเราลองพิจารณาบทบาทหน้าที่ของ σ² ในสมการนี้ดูจะพบว่า มันจะทำหน้าที่บรรเทา (alleviate) ค่าของ loss ให้ลดลงด้วยการหารค่า loss ดั้งเดิมที่เรารู้จัก (term แรกสุดในสมการ) และใน term ที่สองก็คือค่า regularizer ที่เป็นตัวกำหนดไม่ให้ค่าของ σ² มีค่ามากเกินไป เพราะถ้าไม่มีค่านี้ โมเดลอาจจะเรียนรู้แบบขี้โกง คือเพิ่มให้ σ² มีค่ามาก ๆ เพื่อลง loss จาก term แรกให้น้อย ๆ อย่างไร้เหตุผล พอมี term สองนี้บวกเข้ามา ถ้าค่านี้ยิ่งมาก loss ก็จะยิ่งสูงขึ้นด้วย โมเดลก็จะเรียนรู้ที่จะหาจุดที่สมเหตุสมผล

ส่วน term สามนั้นไม่มีอะไร ทำเป็นไม่เห็นก็แล้วกันครับ เพราะมันไม่มีส่วนที่โมเดลเราต้องคำนวณเลย 55+

ทดสอบด้วยการเขียนโค้ด

ทีนี้เรามาลองเขียนโค้ดกันดูว่า โมเดลนี้มันสามารถรันได้จริงรึเปล่า ?? สามารถดูโค้ดได้จากที่นี่ด้วยครับ https://github.com/dopplerz/Regression_secret

ก่อนอื่นเรามาสร้าง training data โดยมีที่มาจากสมการ

μ = x³ – 5x² + 2x + 2

ให้เป็นค่าของ μ และให้มี variance เพิ่มขึ้นเรื่อย σ มีค่าตามสมการ

σ = 3x

import numpy as np
import matplotlib.pyplot as plt
x_train = np.arange(0, 5, 0.001)
mu = x_train**3 - 5*(x_train**2) + 2*x_train + 2
std = 3 - x_train / 2.
y_train = mu + (std * np.random.normal(size=std.shape))
plt.figure(figsize=[12, 6]).add_subplot(111).scatter(
x_train, y_train, marker='.')

โดยเราคาดหวังว่าโมเดลจะ predict ค่าของ mu และ sigma ออกมาหน้าตาแบบนี้

ค่าของ μ ที่อยากให้โมเดลตอบ
ค่าของ σ ที่อยากให้โมเดลตอบ

สร้างโมเดลง่าย ๆ ขึ้นมาหนึ่งโมเดลที่มีผลลัพธ์สองค่าคือ μ กับ σ โดยใช้ loss function ด้านบน (loss function ที่เขียนในโค้ดนี้ทำการตัด term 3 ทิ้งไป และตัด 1/2 ทิ้งไปจากทั้ง term 1 และ 2)

import tensorflow as tf
x = tf.placeholder(tf.float32, [None, 1])
y = tf.placeholder(tf.float32, [None])
learning_rate = tf.placeholder(tf.float32)
out = tf.layers.dense(x, 50, activation=tf.nn.relu)
out = tf.layers.dense(out, 50, activation=tf.nn.relu)
out = tf.layers.dense(out, 50, activation=tf.nn.relu)
y_hat = tf.layers.dense(out, 2)
mu = y_hat[:, 0]
sigma = tf.nn.softplus(y_hat[:, 1])
term_1 = ((y - mu)**2) / (sigma**2)
term_2 = tf.log(sigma**2)
loss = tf.reduce_mean(term_1 + term_2)
optimizer = tf.train.GradientDescentOptimizer(
learning_rate=learning_rate
)
opt = optimizer.minimize(loss)

ลองทดสอบ train โมเดลว่าสามารถหาค่าทั้งสองได้ไหม

sess = tf.Session()
sess.run(tf.global_variables_initializer())
x_train = x_train.reshape([-1, 1])
lr = 0.01
for i in range(15000):
lr = lr / 10. if (i + 1) in [5000, 9000, 12000] else lr
f_dict = {x: x_train, y: y_train, learning_rate: lr}
_, l = sess.run([opt, loss], feed_dict=f_dict)
if (i+1) % 200 == 0:
print("step {} - loss {:.5f}".format(i+1, l))

ทำการ predict ค่าของ mu, sigma ออกมา

f_dict = {x: x_train}
u, sig = sess.run([mu, sigma], feed_dict=f_dict)

และเมื่อแสดงผล จะพบกราฟประมาณนี้

plt.figure(figsize=[12, 6]).add_subplot(111).scatter(
x_train, u, marker=’.’)
ค่าของ μ จากการ predict
plt.figure(figsize=[12, 6]).add_subplot(111).scatter(
x_train, sigma, marker='.')
ค่าของ σ จากการ predict

สรุปว่า

โมเดลของเราสามารถเรียนรู้ค่า y ได้ตามปกติ ตามความสามารถของ regression model และยังสามารถที่จะเรียนรู้ได้ว่าค่า x ช่วงไหนที่จะให้ผลลัพธ์ที่มีความไม่แน่นอนสูง (high uncertainty) ด้วย ซึ่งปกติแล้วค่าของความไม่แน่นอนนี้จะไม่ถูกนำมาคิดในกรณีของ regression ทั่วไป

Source: Deep Learning on Medium