กลับไปยังโจทย์
ยาก 0 ข้อที่แก้แล้ว อัตราผ่าน 0%

การแพร่ย้อนกลับในโครงข่ายสองชั้น

คำนวณเกรเดียนต์ของน้ำหนักและไบแอสทั้งหมดในโครงข่ายที่มีเลเยอร์ซ่อน sigmoid หนึ่งชั้นและเอาต์พุต sigmoid หนึ่งตัว

สิ่งที่คุณจะได้เรียนรู้

  • คำนวณทุก gradient ของโครงข่ายสองชั้น
  • ส่งค่าความผิดพลาดย้อนกลับผ่านชั้นต่าง ๆ
  • เชื่อมคณิตศาสตร์กับโค้ดทีละขั้น

โจทย์

การแพร่ย้อนกลับ ใช้กฎลูกโซ่ทีละเลเยอร์ จากเอาต์พุตย้อนกลับไปหาอินพุต โครงข่ายมีอินพุต n ตัว นิวรอนซ่อน h ตัว และเอาต์พุตหนึ่งตัว ทั้งหมดใช้ sigmoid (σ(z) = 1 / (1 + e^(-z))):

  • เลเยอร์ซ่อน: a_j = σ(inputs · hidden_weights[j] + hidden_biases[j])
  • เอาต์พุต: y = σ(a · output_weights + output_bias)
  • ค่าสูญเสีย: L = (y - target)²

เกรเดียนต์:

  1. delta_out = 2 × (y - target) × y × (1 - y)
  2. เลเยอร์เอาต์พุต: dL/doutput_weights[j] = delta_out × a_j และ dL/doutput_bias = delta_out
  3. delta_j = delta_out × output_weights[j] × a_j × (1 - a_j)
  4. เลเยอร์ซ่อน: dL/dhidden_weights[j][i] = delta_j × inputs[i] และ dL/dhidden_biases[j] = delta_j

จงเขียน backprop_gradients(inputs, hidden_weights, hidden_biases, output_weights, output_bias, target)

เอาต์พุต

คืนค่าเมทริกซ์ที่มี h + 1 แถว:

  • แถว j (สำหรับนิวรอนซ่อน j แต่ละตัวตามลำดับ): เกรเดียนต์ n ค่าของ hidden_weights[j] แล้วตามด้วยเกรเดียนต์ของ hidden_biases[j]
  • แถวสุดท้าย: เกรเดียนต์ h ค่าของ output_weights แล้วตามด้วยเกรเดียนต์ของ output_bias

เงื่อนไข

1 ≤ n, h ≤ 20

-5 ≤ อินพุต น้ำหนัก และไบแอสแต่ละค่า ≤ 5

0 ≤ target ≤ 1

ตัวอย่าง

ตัวอย่างที่ 1
อินพุต:
inputs = [1.0]
target = 1.0
output_bias = 0.0
hidden_biases = [0.0]
hidden_weights = [
    [0.0]
]
output_weights = [0.0]

ผลลัพธ์ที่คาดหวัง:
expected = [
    [0.0, 0.0],
    [-0.125, -0.25]
]
อินพุต:
std::vector<double> inputs = {1.0};
double target = 1.0;
double output_bias = 0.0;
std::vector<double> hidden_biases = {0.0};
std::vector<std::vector<double>> hidden_weights = {
    {0.0}
};
std::vector<double> output_weights = {0.0};

ผลลัพธ์ที่คาดหวัง:
std::vector<std::vector<double>> expected = {
    {0.0, 0.0},
    {-0.125, -0.25}
};
อินพุต:
double[] inputs = new double[] {1.0};
double target = 1.0;
double output_bias = 0.0;
double[] hidden_biases = new double[] {0.0};
double[][] hidden_weights = new double[][] {
    new double[] {0.0}
};
double[] output_weights = new double[] {0.0};

ผลลัพธ์ที่คาดหวัง:
double[][] expected = new double[][] {
    new double[] {0.0, 0.0},
    new double[] {-0.125, -0.25}
};

คำอธิบาย

a = σ(0) = 0.5 และ y = σ(0) = 0.5 delta_out = 2 × (0.5 - 1) × 0.25 = -0.25 แถวเอาต์พุต: [-0.25 × 0.5, -0.25] = [-0.125, -0.25] delta_1 = -0.25 × 0 × 0.25 = 0 ดังนั้นแถวซ่อนคือ [0, 0]: น้ำหนักเอาต์พุตที่เป็นศูนย์จะกั้นเกรเดียนต์ไว้

ตัวอย่างที่ 2
อินพุต:
inputs = [1.0, 0.0]
target = 0.0
output_bias = -1.0
hidden_biases = [0.0, 0.0]
hidden_weights = [
    [0.0, 1.0],
    [0.0, -1.0]
]
output_weights = [1.0, 1.0]

ผลลัพธ์ที่คาดหวัง:
expected = [
    [0.0625, 0.0, 0.0625],
    [0.0625, 0.0, 0.0625],
    [0.125, 0.125, 0.25]
]
อินพุต:
std::vector<double> inputs = {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
std::vector<double> hidden_biases = {0.0, 0.0};
std::vector<std::vector<double>> hidden_weights = {
    {0.0, 1.0},
    {0.0, -1.0}
};
std::vector<double> output_weights = {1.0, 1.0};

ผลลัพธ์ที่คาดหวัง:
std::vector<std::vector<double>> expected = {
    {0.0625, 0.0, 0.0625},
    {0.0625, 0.0, 0.0625},
    {0.125, 0.125, 0.25}
};
อินพุต:
double[] inputs = new double[] {1.0, 0.0};
double target = 0.0;
double output_bias = -1.0;
double[] hidden_biases = new double[] {0.0, 0.0};
double[][] hidden_weights = new double[][] {
    new double[] {0.0, 1.0},
    new double[] {0.0, -1.0}
};
double[] output_weights = new double[] {1.0, 1.0};

ผลลัพธ์ที่คาดหวัง:
double[][] expected = new double[][] {
    new double[] {0.0625, 0.0, 0.0625},
    new double[] {0.0625, 0.0, 0.0625},
    new double[] {0.125, 0.125, 0.25}
};

คำอธิบาย

ค่าซ่อนทั้งสองค่าเท่ากับ σ(0) = 0.5 ดังนั้น y = σ(0.5 + 0.5 - 1) = 0.5 และ delta_out = 2 × 0.5 × 0.25 = 0.25 แถวเอาต์พุต: [0.125, 0.125, 0.25] delta_j แต่ละค่า = 0.25 × 1 × 0.25 = 0.0625 ได้แถวซ่อน [0.0625, 0, 0.0625] (อินพุตตัวที่สองเป็น 0)

แนวทางการแก้

ลองทำเองก่อน แล้วค่อยเปิดคำใบ้ทีละข้อ

คำใบ้ 1

ไล่ย้อนจาก output neuron ก่อน แล้วใช้สัญญาณนั้นคำนวณส่วนที่ hidden neuron แต่ละตัวมีส่วนร่วม

คำใบ้ 2

คุณต้องมี delta หนึ่งตัวสำหรับ output layer และอีกหนึ่งตัวต่อ hidden neuron โดยทั้งคู่ขึ้นกับอนุพันธ์ของ sigmoid

คำใบ้ 3

ระวังต้องใช้ output weight ของ hidden neuron แต่ละตัวเองในการส่ง error ย้อนกลับไปยัง neuron นั้น

ความซับซ้อนที่คาดหวัง

เวลา O(hn), หน่วยความจำเพิ่ม O(hn)

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

โจทย์นี้ปรับให้เหมาะกับ CodeUtility กรุณาทำตามคำชี้แจงและข้อจำกัดด้านบน

เรียนรู้จากคนอื่น

แนวทางจากชุมชน

ยังไม่มีวิธีทำที่เผยแพร่ ลองแก้โจทย์นี้เพื่อแชร์วิธีแรก