แผนการเรียนรู้
/

การบ้านสัปดาห์ที่ 11

Timeseries LSTM Dashboard

สร้าง Django dashboard สำหรับทำนายข้อมูลอนุกรมเวลาด้วย LSTM

1. ข้อกำหนดโครงงาน

2. โครงสร้าง Django project

3. สิ่งที่ต้องทำใน ml/train.py

4. หน้า landing page

5. วิธีรันและตรวจสอบ

6. การส่งงาน

ข้อกำหนดโครงงาน

- โมเดล: LSTM สำหรับทำนายอุณหภูมิ (หรือข้อมูลอนุกรมเวลาอื่น)

- ข้อมูล: ใช้ sliding window — เปลี่ยนข้อมูลอนุกรมเวลาเป็น supervised learning

- Train/Val split: แบ่งข้อมูลฝึกสอนและตรวจสอบ

- Dashboard: SSE streaming แสดง loss, ผลทำนายแบบ real-time

- หน้า landing: แสดง รหัสนักศึกษา และ ชื่อ-นามสกุล (hardcoded)

[สำคัญ] ใช้ Django + PyTorch LSTM เท่านั้น ห้ามใช้ TensorFlow

# ผลลัพธ์ที่คาดหวัง:

1. เริ่ม server แล้วเห็นหน้า landing page
   ที่มีรหัสนักศึกษาและชื่อ-นามสกุล

2. กดปุ่ม "เริ่มฝึกสอน" แล้วเห็น
   - ค่า loss ลดลงแบบ real-time
   - กราฟ training loss อัปเดตทุก epoch

3. หลังฝึกสอนเสร็จ แสดงผลลัพธ์
   - กราฟ predicted vs actual values
   - ค่า MSE/RMSE บน validation set

4. หน้า landing page แสดงรหัสและชื่อ
   ของนักศึกษาที่ทำโครงงาน

โครงสร้าง Django Project

DL69/wk11/
├── pyproject.toml           # uv project, Python 3.13
├── manage.py
├── mysite/
│   ├── __init__.py
│   ├── settings.py
│   ├── urls.py
│   └── wsgi.py
├── dashboard/
│   ├── __init__.py
│   ├── apps.py
│   ├── views.py             # SSE streaming endpoint
│   ├── urls.py              # / → index, /train/ → SSE
│   ├── ml/
│   │   ├── __init__.py
│   │   └── train.py         # ★ นักศึกษาเขียนโค้ดตรงนี้
│   ├── templates/
│   │   └── dashboard/
│   │       └── index.html    # ★ ใส่รหัสและชื่อตรงนี้
│   └── static/
│       └── dashboard/
│           └── (ผลลัพธ์จาก train.py)
└── data/                     # ชุดข้อมูลอนุกรมเวลา

- pyproject.toml: กำหนด dependencies สำหรับ uv sync

- dashboard/ml/train.py: ไฟล์หลักที่นักศึกษาต้องเขียน

- dashboard/templates/dashboard/index.html: หน้า landing page

- data/: ใส่ข้อมูลอนุกรมเวลา (เช่น CSV อุณหภูมิ)

[สำคัญ] ห้ามลบหรือแก้ไขไฟล์ที่ไม่ได้ระบุว่าต้องแก้ — ใช้ไฟล์เดิมที่ให้มา

สิ่งที่ต้องทำใน ml/train.py

def train(on_progress=None):
    """
    on_progress(epoch, loss, val_loss) → เรียกทุก epoch
    """
    import torch
    import torch.nn as nn

    # 1. โหลดข้อมูลอนุกรมเวลา
    #    data = read_csv('data/temperature.csv')

    # 2. Sliding window → supervised learning
    #    window_size = 24  (เช่น 24 ชั่วโมงย้อนหลัง)
    #    X[i] = data[i:i+window_size]
    #    y[i] = data[i+window_size]

    # 3. Train/Val split (80/20)

    # 4. สร้างโมเดล LSTM
    class LSTMModel(nn.Module):
        def __init__(self):
            super().__init__()
            self.lstm = nn.LSTM(input_size=1,
                              hidden_size=64,
                              num_layers=2,
                              batch_first=True)
            self.fc = nn.Linear(64, 1)

        def forward(self, x):
            out, _ = self.lstm(x)
            return self.fc(out[:, -1, :])

    # 5. Training loop
    for epoch in range(num_epochs):
        # forward, loss, backward, step
        # เรียก on_progress(epoch, loss, val_loss)
        pass

    # 6. บันทึกผลลัพธ์
    #    - predicted vs actual plot → PNG
    #    - training loss curve → PNG

- ข้อ 1: โหลดข้อมูล CSV แล้วแปลงเป็น sliding window

- ข้อ 2: สร้าง LSTM model ด้วย nn.LSTM

- ข้อ 3: Training loop พร้อม train/val split

- ข้อ 4: เรียก on_progress(epoch, loss, val_loss) ทุก epoch

- ข้อ 5: บันทึกกราฟ predicted vs actual เป็น PNG

[เคล็ดลับ] ดู code ตัวอย่างจาก wk11.html slides เป็นแนวทาง

หน้า Landing Page

<!-- dashboard/templates/dashboard/index.html -->
<!DOCTYPE html>
<html lang="th">
<head>
  <title>Timeseries LSTM Dashboard</title>
  <script defer src="https://cdn.jsdelivr.net/npm/alpinejs@3.x.x/dist/cdn.min.js"></script>
  <script src="https://cdn.tailwindcss.com"></script>
</head>
<body x-data="{ training: false, epoch: 0, loss: 0, valLoss: 0 }">

  <!-- ★ ใส่รหัสนักศึกษาและชื่อ-นามสกุลตรงนี้ -->
  <h1>รหัสนักศึกษา: 69000000</h1>
  <h2>ชื่อ-นามสกุล: ชื่อ นามสกุล</h2>

  <button @click="startTraining()">
    เริ่มฝึกสอน
  </button>

  <p>Epoch: <span x-text="epoch"></span></p>
  <p>Loss: <span x-text="loss"></span></p>
  <p>Val Loss: <span x-text="valLoss"></span></p>

  <canvas id="chart"></canvas>

  <script>
  function startTraining() {
    training = true;
    const es = new EventSource('/train/');
    es.onmessage = function(e) {
      const m = JSON.parse(e.data);
      epoch = m.epoch;
      loss = m.loss.toFixed(4);
      valLoss = m.val_loss.toFixed(4);
      drawChart(m.epoch, m.loss, m.val_loss);
    };
  }
  </script>
</body>
</html>

- รหัสนักศึกษา: เปลี่ยน 69000000 เป็นรหัสจริง

- ชื่อ-นามสกุล: เปลี่ยน ชื่อ นามสกุล เป็นชื่อจริง

- ปุ่ม "เริ่มฝึกสอน" เชื่อมกับ SSE endpoint

- แสดงทั้ง training loss และ validation loss

- ใช้ Canvas หรือ Chart.js สำหรับกราฟ

[สำคัญ] ห้ามลบ student ID และชื่อออกจากหน้า — ต้องเห็นชัดเจนเมื่อเปิดหน้า

วิธีรันและตรวจสอบ

# 1. Clone repo และ checkout branch
git clone <DL69-repo>
cd DL69
git checkout wk11

# 2. ติดตั้ง dependencies
uv sync

# 3. รัน server
uv run manage.py runserver

# 4. เปิดเบราว์เซอร์
#    http://127.0.0.1:8000/
#    → เห็นรหัสนักศึกษาและชื่อ
#    → กด "เริ่มฝึกสอน"
#    → เห็น loss, val_loss อัปเดตแบบ real-time
#    → หลังฝึกเสร็จ เห็น predicted vs actual plot

# 5. ตรวจสอบไฟล์ผลลัพธ์
ls dashboard/static/dashboard/
#    → loss_curve.png
#    → prediction_plot.png

- ขั้นตอนที่ 1: Clone repo แล้ว checkout branch wk11

- ขั้นตอนที่ 2: รัน uv sync เพื่อติดตั้ง dependencies

- ขั้นตอนที่ 3: รัน uv run manage.py runserver

- ขั้นตอนที่ 4: เปิด http://127.0.0.1:8000/

- ขั้นตอนที่ 5: ตรวจสอบว่าหน้า landing แสดงรหัสและชื่อ

[สำคัญ] ต้องรันได้ด้วย uv sync + uv run manage.py runserver เท่านั้น

การส่งงาน

- Branch name: wk11

- Repo: DL69 (GitHub repository ของนักศึกษา)

- สร้าง branch ใหม่จาก main

- Commit โค้ดทั้งหมดลง branch wk11

- Push ขึ้น GitHub

- แจ้ง URL ของ repo ให้อาจารย์

[สำคัญ] ห้าม commit ไฟล์ data ขนาดใหญ่ (>10MB) — ใช้ .gitignore

# สร้างและ push branch
git checkout -b wk11
git add .
git commit -m "wk11: Timeseries LSTM Dashboard"
git push origin wk11

# โครงสร้างไฟล์ที่ต้องมี
DL69/wk11/
├── pyproject.toml
├── manage.py
├── mysite/
├── dashboard/
│   ├── views.py
│   ├── ml/train.py       ← โค้ดที่เขียน
│   └── templates/
│       └── dashboard/
│           └── index.html ← ใส่รหัส+ชื่อ
└── data/
    └── temperature.csv   ← ข้อมูล

# ตรวจสอบก่อนส่ง
uv sync
uv run manage.py runserver
# → หน้า landing แสดงรหัสและชื่อ
# → กดเริ่มฝึกสอน → SSE ทำงาน
# → ได้ prediction_plot.png

เกณฑ์การให้คะแนน

- โมเดลถูกต้อง (30%): LSTM + sliding window ทำงานได้

- SSE Streaming (20%): ฝึกสอนแบบ real-time ได้

- หน้า landing (15%): แสดงรหัสและชื่อชัดเจน

- ผลลัพธ์ (15%): predicted vs actual plot, MSE/RMSE

- โค้ดสะอาด (10%): โครงสร้างดี, มี docstring

- รันได้จริง (10%): uv sync + runserver ไม่ error

[คะแนนรวม] 100% = คะแนนการบ้านสัปดาห์ที่ 11

# ตรวจสอบก่อนส่ง:

# 1. uv sync สำเร็จ?
uv sync

# 2. server รันได้?
uv run manage.py runserver

# 3. หน้า landing แสดงรหัส+ชื่อ?
#    เปิด http://127.0.0.1:8000/

# 4. SSE ทำงาน?
#    กด "เริ่มฝึกสอน" แล้วเห็น
#    epoch, loss, val_loss อัปเดต

# 5. ผลลัพธ์ครบถ้วน?
#    - loss_curve.png มีอยู่
#    - prediction_plot.png มีอยู่

# 6. Branch ชื่อ wk11?
git branch
#    → * wk11