สอนสร้าง MLP จำลองการทำงานแบบ RNN ด้วย Java Neuroph

Recurrent Neural Networks (RNNs) เป็นรูปแบบหนึ่งของโครงข่ายประสาทเทียมที่มีความสามารถในการจัดการข้อมูลที่มีลำดับ เช่น ข้อมูลเวลา (time series) หรือข้อความ (text sequences) อย่างไรก็ตาม Neuroph ซึ่งเป็นเฟรมเวิร์ก Java สำหรับสร้างและฝึกโครงข่ายประสาทเทียม ไม่มีการสนับสนุน RNN โดยตรง แต่สามารถปรับ Multilayer Perceptron (MLP) ให้ทำงานแบบ RNN ได้ด้วยการเพิ่มการจัดการสถานะ (state) ภายนอก

แนวคิดหลัก

  1. ใช้ MLP เป็นฐานของโครงข่ายประสาทเทียม
  2. เพิ่มกลไกการวนกลับ (feedback) โดยจัดเก็บผลลัพธ์ของเลเยอร์ซ่อน (hidden layer) และนำกลับมาใช้ใหม่ในลำดับถัดไป
  3. จัดการการทำงานที่คล้าย RNN ผ่านการเขียนโค้ดควบคุมภายนอก

ขั้นตอนการจำลอง RNN ด้วย MLP ใน Neuroph

  1. เตรียมข้อมูล: จัดการข้อมูลสำหรับการเรียนรู้แบบลำดับ เช่น การพยากรณ์ค่าถัดไปในลำดับตัวเลข (เช่น ลำดับ Fibonacci)
  2. สร้างโครงข่าย MLP: สร้างโครงข่าย MLP ด้วยเลเยอร์อินพุต เลเยอร์ซ่อน และเลเยอร์เอาต์พุต
  3. เพิ่มกลไก Feedback: เก็บค่าผลลัพธ์ของเลเยอร์ซ่อนในแต่ละลำดับ และรวมค่าดังกล่าวกับอินพุตใหม่
  4. การฝึกโครงข่าย: ใช้ค่าความผิดพลาด (error) ในการปรับน้ำหนักของโครงข่าย โดยใช้กฎการเรียนรู้ที่มีใน Neuroph
  5. การทดสอบ: ใช้โครงข่ายที่ผ่านการฝึกทำนายค่าถัดไปในลำดับและตรวจสอบความแม่นยำ

ตัวอย่างโค้ด

ตัวอย่างนี้แสดงการสร้างและฝึกโครงข่าย MLP ให้ทำงานแบบ RNN ด้วยการจำลองการพยากรณ์ค่าถัดไปในลำดับ Fibonacci:

import org.neuroph.core.Layer;
import org.neuroph.core.Neuron;
import org.neuroph.core.Connection;
import org.neuroph.nnet.MultiLayerPerceptron;

public class SimulatedRNN {
    public static void main(String[] args) {
        // สร้างโครงข่าย MLP
        MultiLayerPerceptron mlp = new MultiLayerPerceptron(2, 4, 1); // อินพุต 2, ซ่อน 4, เอาต์พุต 1

        // ข้อมูลสำหรับฝึก
        double[][] inputSequence = {
            {0.0, 1.0},
            {1.0, 1.0},
            {1.0, 2.0},
            {2.0, 3.0},
            {3.0, 5.0}
        };
        double[] expectedOutputs = {1.0, 2.0, 3.0, 5.0, 8.0};

        // สถานะซ่อนสำหรับ Feedback
        double[] previousHiddenStates = new double[4];

        // วนลูปการฝึก
        for (int epoch = 0; epoch < 1000; epoch++) {
            double totalError = 0.0;
            for (int t = 0; t < inputSequence.length; t++) {
                // รวมอินพุตปัจจุบันกับสถานะก่อนหน้า
                double[] currentInput = inputSequence[t];
                double[] fullInput = new double[currentInput.length + previousHiddenStates.length];
                System.arraycopy(currentInput, 0, fullInput, 0, currentInput.length);
                System.arraycopy(previousHiddenStates, 0, fullInput, currentInput.length, previousHiddenStates.length);

                // ตั้งค่าอินพุตให้โครงข่าย
                mlp.setInput(fullInput);

                // คำนวณผลลัพธ์
                mlp.calculate();
                double output = mlp.getOutput()[0];

                // คำนวณความผิดพลาด
                double error = expectedOutputs[t] - output;
                totalError += error * error;

                // ฝึกโครงข่าย
                mlp.getLearningRule().doLearningEpoch();

                // เก็บสถานะของเลเยอร์ซ่อน
                Layer hiddenLayer = mlp.getLayerAt(1);
                for (int i = 0; i < hiddenLayer.getNeuronsCount(); i++) {
                    previousHiddenStates[i] = hiddenLayer.getNeuron(i).getOutput();
                }
            }

            // แสดงผลความผิดพลาดในแต่ละ epoch
            if (epoch % 100 == 0) {
                System.out.println("Epoch " + epoch + " - Error: " + totalError);
            }
        }

        // ทดสอบโครงข่าย
        System.out.println("\nTesting the network:");
        for (int t = 0; t < inputSequence.length; t++) {
            double[] currentInput = inputSequence[t];
            double[] fullInput = new double[currentInput.length + previousHiddenStates.length];
            System.arraycopy(currentInput, 0, fullInput, 0, currentInput.length);
            System.arraycopy(previousHiddenStates, 0, fullInput, currentInput.length, previousHiddenStates.length);

            mlp.setInput(fullInput);
            mlp.calculate();
            double output = mlp.getOutput()[0];
            System.out.println("Input: " + currentInput[0] + ", " + currentInput[1] + " -> Predicted: " + output);
        }
    }
}

สรุป

การใช้ Neuroph จำลอง RNN โดยปรับ Multilayer Perceptron (MLP) สามารถทำได้ผ่านการจัดการสถานะภายนอก ซึ่งช่วยให้โครงข่ายมีความสามารถในการเรียนรู้และทำนายข้อมูลที่มีลำดับได้ แม้ว่าจะไม่ใช่โครงสร้าง RNN ที่แท้จริง แต่แนวทางนี้เหมาะสำหรับการศึกษาแนวคิดพื้นฐานและการทดลองที่ไม่ซับซ้อนมากนัก หากต้องการโครงข่าย RNN ที่มีความซับซ้อนมากขึ้น อาจต้องพิจารณาเฟรมเวิร์กอื่น เช่น TensorFlow หรือ DL4J ที่สนับสนุน RNN โดยตรง

ความคิดเห็น

โพสต์ยอดนิยมจากบล็อกนี้

การใช้งาน RPC (Remote Procedure Call) ด้วย Java พร้อมตัวอย่างเกมออนไลน์ (ต่อ)

เริ่มต้นสร้าง Quiz Widgets แบบสอบถามบนเว็บกัน

การใช้งาน RPC (Remote Procedure Call) ด้วย Java พร้อมตัวอย่างเกมออนไลน์อย่างง่าย