Deep Learning HW5 ทำ Regularization ไม่ให้ overfit

NakarinSTK
Nov 5 · 3 min read

หนึ่งในสิ่งที่ต้องปรับสำหรับในการทำ Neuron Network เพื่อทำการ Predict ก็คือจำนวนชั้นเเละจำนวนNeuron ในเเต่ละชั้น คำถามคือ จะรู้ได้ยังไงว่าต้องใช้กี่ชั้น ชั้นละกี่ Neuron?

เอาตรงๆเเล้วก็ยังไม่มีทฤษฎีที่หาตัวเลขออกมาได้เป๊ะๆนะครับ เเต่ก็มีหลักการที่ว่า ยิ่งชั้นเยอะ function ก็จะยิ่งซ้อนๆกันไปเรื่อยๆ ทำให้ model ของเราคำนวน function ยากๆได้ครับ หรือก็คือยิ่ง model ลึกเท่าไหร่ ก็ยิ่งดีครับ เเต่ก็ต้องเเลกมากับเวลาที่ใช้คำนวนเพิ่มขึ้นครับ ถึงอย่างนั้นเวลาทำ model ผมก็จะอัดให้มัน deep ที่สุดก่อน เเล้วค่อยปรับตัวเลขลงครับ ซึ่งในวันนี้ก็เหมือนกันครับ เราจะมาทำให้ model overfit กัน เเล้วค่อยใช้เทคนิคต่างๆไม่ให้มัน overfit ครับ เทคนิคเเรกคือ L2-Reguularizaton เเล้วก็อีกเทคนิคคือ dropout ครับ

สำหรับ L2-Regularization นั้นเราจะเพิ่มตัวแปรบางตัวแปรเข้าไปใน loss function ครับ ซึ่งตัวแปรนั้นก็คือผลรวมของ weight ในทุกชั้นนั่นเองครับ เเละ lambda ก็เป็นค่าคงที่เฉยๆ

หลักการของมันก็คือ เนื่องจากเราไม่อยากให้ model overfit ดังนั้นค่า weight ของทุกชั้นรวมกันต้องน้อยที่สุด เพราะถ้า weight ยิ่งเยอะ ค่า loss ก็จะเยอะตามครับ ซึ่งการเพิ่มพจน์นี้เข้าไป ก็ทำให้ทั้งการคิด Cost เเละ Backward Propagation เปลี่ยนครับ

อีกเเบบนึงก็คือ drop out ครับ หลักการก็คือเราจะ “สุ่ม” ปิด neuron บางตัวไม่ให้มันทำงานครับ ดังนั้น model ของเราก็จะทำงานได้ไม่ 100% หรือจะบอกว่าติ๊กต๊องขึ้นก็ได้ครับ เเล้วการทำเเบบนี้ยังจะบังคับให้ neuron ทุกตัวทำงานครับ เพราะเพื่อนมันหายไปบางส่วน ถ้าไม่ทำเดี๋ยวจะไม่มีคำตอบ คำว่าไม่ทำงานคือ weight มันเข้าใกล้ 0 มากๆครับ เรียกได้ว่ามีหรือไม่มีก็ไม่ต่างกัน เลยมองว่ามันไม่ทำงานนั่นเองครับ

ถึงตรงนี้ model ของเราดูจะเเบ่งข้อมูลได้เหมาะสมกว่าเเบบไม่ทำ regularization ครับ นอกจากวิธีเหล่านี้เเล้ว การปรับตัวเลขของชั้น ,การลด neuron ในเเต่ละชั้น , การทำ early stop หรือ หยุดเรียนก่อนจะ converge ก็ช่วยเหมือนกันครับ ซึ่งก็เป็นหนึ่งใน state-of-the-art ที่ต้องลองไปปรับๆกันดู

จบไปเเล้วสำหรับเนื้อหา ต่อไป็จะเป็นตัวอย่างโค้ดครับ เนื่องจากมีการปรับการทำงาน จึงต้องมีการเขียน funtion สำหรับ model ใหม่ครับ

L2-Regularization

# ค่า Cost ใหม่ของ log-loss ครับ
def compute_cost_with_regularization(A3, Y, parameters, lambd):
m = Y.shape[1]
W1 = parameters["W1"]
W2 = parameters["W2"]
W3 = parameters["W3"]

cross_entropy_cost = compute_cost(A3, Y)
L2_regularization_cost = ((np.sum(np.square(W1)) +np.sum(np.square(W2)) +np.sum(np.square(W3))) * (lambd/(2*m)))

cost = cross_entropy_cost + L2_regularization_cost

return cost
# คำนวน back propagation ต่างออกไปเล็กน้อย
def backward_propagation_with_regularization(X, Y, cache, lambd):
m = X.shape[1]
(Z1, A1, W1, b1, Z2, A2, W2, b2, Z3, A3, W3, b3) = cache

dZ3 = A3 - Y

dW3 = 1./m * np.dot(dZ3, A2.T) + lambd*W3/m
db3 = 1./m * np.sum(dZ3, axis=1, keepdims = True)

dA2 = np.dot(W3.T, dZ3)
dZ2 = np.multiply(dA2, np.int64(A2 > 0))
dW2 = 1./m * np.dot(dZ2, A1.T) + lambd*W2/m
db2 = 1./m * np.sum(dZ2, axis=1, keepdims = True)

dA1 = np.dot(W2.T, dZ2)
dZ1 = np.multiply(dA1, np.int64(A1 > 0))
dW1 = 1./m * np.dot(dZ1, X.T) + lambd*W1/m
db1 = 1./m * np.sum(dZ1, axis=1, keepdims = True)

gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
"dZ1": dZ1, "dW1": dW1, "db1": db1}

return gradients

Dropout

# LINEAR -> RELU -> LINEAR -> RELU -> LINEAR -> SIGMOID
def forward_propagation_with_dropout(X, parameters, keep_prob = 0.5):

W1 = parameters["W1"]
b1 = parameters["b1"]
W2 = parameters["W2"]
b2 = parameters["b2"]
W3 = parameters["W3"]
b3 = parameters["b3"]
Z1 = np.dot(W1, X) + b1
A1 = relu(Z1)
D1 = np.random.rand(A1.shape[0], A1.shape[1])
D1 = D1<keep_prob
A1 = np.multiply(A1,D1)
A1 = A1/keep_prob
Z2 = np.dot(W2, A1) + b2
A2 = relu(Z2)

D2 = np.random.rand(A2.shape[0], A2.shape[1])
D2 = D2<keep_prob
A2 = np.multiply(A2,D2)
A2 = A2/keep_prob
Z3 = np.dot(W3, A2) + b3
A3 = sigmoid(Z3)

cache = (Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3)

return A3, cache
def backward_propagation_with_dropout(X, Y, cache, keep_prob):
m = X.shape[1]
(Z1, D1, A1, W1, b1, Z2, D2, A2, W2, b2, Z3, A3, W3, b3) = cache

dZ3 = A3 - Y
dW3 = 1./m * np.dot(dZ3, A2.T)
db3 = 1./m * np.sum(dZ3, axis=1, keepdims = True)
dA2 = np.dot(W3.T, dZ3)

dA2 = np.multiply(dA2,D2)
dA2 = dA2 / keep_prob
dZ2 = np.multiply(dA2, np.int64(A2 > 0))
dW2 = 1./m * np.dot(dZ2, A1.T)
db2 = 1./m * np.sum(dZ2, axis=1, keepdims = True)

dA1 = np.dot(W2.T, dZ2)
dA1 = np.multiply(dA1,D1)
dA1 = dA1 / keep_prob
dZ1 = np.multiply(dA1, np.int64(A1 > 0))
dW1 = 1./m * np.dot(dZ1, X.T)
db1 = 1./m * np.sum(dZ1, axis=1, keepdims = True)

gradients = {"dZ3": dZ3, "dW3": dW3, "db3": db3,"dA2": dA2,
"dZ2": dZ2, "dW2": dW2, "db2": db2, "dA1": dA1,
"dZ1": dZ1, "dW1": dW1, "db1": db1}

return gradients

    NakarinSTK

    Written by

    Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
    Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
    Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade