Day: August 18, 2021

  • วิธีรัน Jupyter Notebook, ปิด browser แล้วระบบส่ง LINE บอกพร้อมภาพ เมื่อเสร็จแล้ว ค่อยกลับมาดูผล

    ปัจจุบัน งานด้าน Data Science ก็มักจะใช้ Jupyter Notebook เพราะสะดวกในการทดลอง ทดสอบ ทำทีละบรรทัด ดูผล ปรับแต่งไปได้เรื่อย ๆ แถมสามารถซื้อ Server ส่วนกลาง ลงทุน GPU แล้วใช้พร้อม ๆ กันหลาย ๆ คนทั้งทีมก็ได้

    ปัญหาอยู่ตรงที่ การสร้าง Model มักจะใช้เวลานาน (มาก) แล้ว Jupyter มันเป็น Web-based จะปิด Browser ก็ได้ แต่หลายคนคงเคยเจอว่า พอกลับมาเปิด URL เดิม ก็ไม่เห็นผลที่รันแล้ว

    จริง ๆ แล้วคือ Jupyter Notebook นั้น ทำงานต่อไป จนเสร็จแล้วแหล่ะ แต่ เว็บ Browser น่าจะไม่สามารถต่อ Session ได้ (หวังว่าจะนึกภาพออก) ที่สำคัญ มันรันนานมาก เสร็จเมื่อไหร่ก็ไม่รู้ แล้วจะรู้ได้อย่างไรว่าเสร็จ เสร็จแล้วผลเป็นอย่างไร

    ในบทความนี้ จะนำเสนอวิธีการที่ทำให้

    1. สั่งรันงานที่ใช้เวลานาน (ขอยกตัวอย่าง 100 วินาที) แล้วปิด Browser ไปทำอย่างอื่นต่อได้เลย
    2. เมื่อระบบทำงานเสร็จ จะแจ้ง LINE Notify พร้อมแนบภาพ Graph ผลลัพธ์ ส่งมาด้วย
    3. พอกลับมาเปิด Browser กลับมาใน Jupyter Notebook เดิม สามารถดูผลการรันอื่น ๆ ได้อีกครั้งเหมือนกับไม่ได้ปิด Browser
    ภาพรวม

    เริ่มต้นจาก Import

    import sys
    from IPython.display import clear_output
    import logging
    import sys
    import requests
    import datetime,time,pytz
    import random

    Function ในการส่ง LINE Notify

    เป็นส่วนของ LINE TOKEN และ function “jobdone” ไว้ส่ง LINE Notify สามารถกำหนดข้อความ และกำหนดภาพที่จะแนบได้

    LINE_TOKEN="YOUR-LINE-TOKEN"
    
    def jobdone(LINE_TOKEN, message="Done!", img=None):
        notify_url = 'https://notify-api.line.me/api/notify'
        header={
            'Authorization': "Bearer " + LINE_TOKEN
        }        
        data=({
            'message': message
        })
    
        files = {'imageFile': open(img, 'rb')} if img else None
        session = requests.Session()
        response = session.post(
            notify_url,
            headers=header,
            files=files,
            data=data
        ).json()
        if files:
            files['imageFile'].close()

    Function สำหรับ Plot

    รับข้อมูล และ สร้างภาพเพื่อประกอบการส่ง Line

    import matplotlib.pyplot as plt
    def plot_something(data, resultfilename):
        fig, ax = plt.subplots()
        ax.plot(data)
        ax.grid()
        fig.savefig(resultfilename)
        plt.show()

    ส่วนที่ใช้เวลานาน

    %%capture capture_output
    resultfilename="result.png"
    start_time=time.time()
    
    data=[]
    for i in range(100):
        data.append(random.random()*100)
        time.sleep(1)
    plot_something(data, resultfilename)
    
    duration=time.time()-start_time
    now=datetime.datetime.now(pytz.timezone('Asia/Bangkok')).strftime("%Y-%m-%d %H:%M:%S")
    jobdone(LINE_TOKEN, f'{now} เสร็จแล้วนะโว้ย [{duration:.2f} sec.]', img=resultfilename)

    ตรงนี้ต้องอธิบายเพิ่ม

    ใน Jupyter จะมีสิ่งที่เรียกว่า “magic cell” ในที่นี้คือ

    %%capture capture_output

    โดยที่ %%capture คือคำสั่งที่จะเก็บผลลัพธ์ทุกอย่าง ที่ส่งออกจาก stdout, stderr รวมถึงภาพด้วย ในคำสั่งข้างต้น จะส่งออกไปยัง capture_output ซึ่งจะนำไปใช้ในภายหลัง

    ต่อมา จะจำลองการทำงานที่ยาวนาน คือ random ค่าระหว่าง 1-100 เอาไปใส่ใน array “data” จากนั้น ก็ sleep 1 วินาที รวมแล้ว ขั้นตอนนี้จะทำงาน 100 วินาที หรือ 1 นาที 40 วินาที (ในการทำงานจริง ยาวนานกว่านั้นมาก ๆ)

    เมื่อเสร็จแล้ว plot_something จะเอาข้อมูล data ไป plot แล้วแสดงผล และ save เป็นไฟล์ตามที่กำหนด คือ result.png

    คำสั่งต่อมา เป็นการแสดง วันเวลาปัจจุบัน โดยแสดงเป็น Timezone ของไทย

    สุดท้าย function jobdone กำหนดข้อความ และภาพที่จะส่ง

    Let’s go!

    รอไป 1 นาที 40 วินาที ก็จะได้ LINE Notify (อ่านขั้นตอนการได้มาซึ่ง LINE Token ได้จาก วิธีแจ้งเตือนจาก Google Forms เข้า LINE )

    กลับมาใน Jupyter Notebook

    ใน cell ใหม่ ใช้คำสั่ง

    capture_output()

    ก็จะแสดงผลสิ่งที่ดำเนินการไป ระหว่างนั้นได้ครับ

    หวังว่าจะเป็นประโยชน์ครับ