Wednesday, August 28, 2019

มาลองสร้าง Web back end ด้วย Flask + Python กัน

แน่นอนว่าใครทำงานด้านเขียนโปรแกรมทางวิทยาศาสตร์สายต่างๆ ก็คงคุ้นเคยกับ python ดี แล้วถ้าต้องการเอา python ไปเขียน web back end ล่ะ ก็จะมี python web framework หลายๆตัวที่ใช้งานได้ เช่น django เป็นต้น

วันนี้เรามาลองเล่น python web framework ที่ชื่อว่า flask ดูกัน เค้าบอกว่าเล็กพริกขี้หนูนะตัวนี้

ก่อนอื่นถ้าอยากดูเอกสารรายละเอียดเกี่ยวกับการใช้งาน flask ไปดูได้ที่ https://flask.palletsprojects.com ผมว่าเค้าเขียนไว้ดีมาก

เอาล่ะ มาสรุปแบบคนขี้เกียจกันดีกว่า ว่าจะติดตั้ง flask ยังไง

  • ถ้ายังไม่มี python 3 ให้ติดตั้งก่อน
  • สร้าง Virtual environment สำหรับงาน web นี้ (การสร้าง virtual env นี้ก็มีประโยชน์คือเราจะสามารถติดตั้ง python package ที่เวอร์ชันต่างๆกัน สำหรับแต่ละ environment ได้)
    • สร้างโฟลเดอร์เอาไว้เก็บงาน web เช่น D:\web
    • เปิด command prompt และเข้าไปที่โฟลเดอร์ข้างต้น พิมพ์คำสั่ง
      python -m venv venv
    • คำสั่งข้างต้นจะสร้าง subfolder ชื่อ venv ซึ่งก็จะเป็นโฟลเดอร์ที่เอาไว้ติดตั้ง python package ด้วย
    • ทำการ activate virtual env. นี้ โดยใช้คำสั่ง
      D:\web\venv\Scripts\activate
      จะเห็นว่า command prompt มีชื่อ virtual env. อยู่ข้างหน้า เช่น <venv>D:\web
    • ติดตั้ง flask โดยพิมพ์
      pip install flask
      เสร็จแล้วจ้า
ต่อมา มาทดสอบกัน
  •  สร้างไฟล์ python เช่น D:\web\server.py
  • เขียนโค้ดตามนี้เลย
from flask import Flask
app = Flask(__name__)

@app.route('/')
def hello_world():
    return 'Hello, World!'

ถ้าจะรันไฟล์นี้ ก็จะใช้คำสั่ง
<venv>D:\web\set FLASK_APP=server.py

จากนั้นเราก็พร้อมสั่งให้ flask ประมวลผลไฟล์ server.py และทำตัวเองเป็น server ที่ port 5000 ด้วยคำสั่ง
<venv>D:\web\flask run

ถ้าไม่มีข้อความผิดพลาด เปิดเว็บแล้วเช็คที่ localhost:5000 ได้เลย

ที่เหลือลองไปเล่นกันต่อเองนะครับ

ลาเต้ช็อคโกแลต (Chocolatey) ร้อนๆจ้า

ดูจากหัวข้อแล้วน่าจะเกี่ยวกับของกิน แต่จริงๆแล้วไม่ใช่ครับ โพสไปอย่างงั้นแหละ

วันนี้ผมจะมาแนะนำ Software package manager สำหรับ Windows ชื่อว่า Chocolatey ซึ่งคนส่วนใหญ่น่าจะรู้จักดีแล้ว ถ้าเทียบกับระบบปฏิบัติการอื่น Chocolatey ก็คือ brew ใน mac หรือ apt-get ใน linux นั่นเองครับ

คำถามคือ มันจะมีประโยชน์อันใด ใน Windows ลงโปรแกรมง่ายจะตาย ดาวน์โหลดแล้วดับเบิลคลิก จากนั้นก็ Next next next... เป็นอันจบ

คำตอบก็คง
  • ใช้ลงโปรแกรมได้ง่ายแบบออนไลน์ (เฉพาะโปรแกรมที่ Chololatey เตรียมไว้ให้ แต่ก็มีมากอยู่นะ โดยเฉพาะสายนักพัฒนา ดูโปรแกรมทั้งหมดได้ที่ https://chocolatey.org/packages)
  • ลงโปรแกรมแล้ว อัพเดท หรือ ถอนการติดตั้งได้ง่าย
  • บางโปรแกรมลงแล้วไม่ต้องมานั่งกำหนด path เอง
  • มีการตรวจสอบความน่าเชื่อถือของโปรแกรมที่จะติดตั้ง
ตัวอย่างเช่น ถ้าเราต้องการติดตั้งซอฟต์แวร์เพื่อเขียน mobile app โดยใช้ react-native
วิธีปกติ ติดตั้ง JDK + set path, NodeJS, python2 (อันนี้ผมไม่แน่ใจว่าใช้ตอนไหน แต่ในเว็บต้นฉบับบอกมา) , Android-SDK (ถ้าต้องการ app สำหรับ Android) เป็นต้น

ถ้าใช้คำสั่งของ Chocolatey เราก็ทำได้ในบรรทัดเดียวเลย เท่ซะไม่มี (แต่เน็ตต้องดีนะครับ)
choco install jdk8 nodejs.install python2 android-sdk

แต่.... จะใช้งาน Chocolatey ก็ต้องรู้ข้อจำกัด นั่นคือ
  • โปรแกรมหรือ package ที่มีให้ อาจจะไม่ใช่เวอร์ชันล่าสุด แล้วแต่ community จะอัพเดท
  •  ไม่มีตัวติดตั้งโปรแกรมเก็บไว้ใช้
  • path หรือโฟลเดอร์ที่ติดตั้งโปรแกรมนั้น อาจจะไม่ใช้ path ที่เราชอบเสมอไปจ้า
เอาล่ะ ถ้าตัดสินใจอยากลอง ก็ไปติดตั้ง Chocolatey กันก่อนได้โดยดูวิธีการจาก https://chocolatey.org/install หรือผมสรุปแบบสั้นๆก็คือ
  1. เปิด command prompt แบบ Admin
  2. แปะคำสั่ง (ความจริงมันเป็นบรรทัดเดียว ถ้าใช้ไม่ได้ให้ไป copy จาก https://chocolatey.org/install นะ)
    @"%SystemRoot%\System32\WindowsPowerShell\v1.0\powershell.exe" 
    -NoProfile -InputFormat None -ExecutionPolicy Bypass 
    -Command "iex ((New-Object System.Net.WebClient).DownloadString
    ('https://chocolatey.org/install.ps1'))" 
    && SET "PATH=%PATH%;%ALLUSERSPROFILE%\chocolatey\bin"
รอจนสำเร็จจ้า
ที่เหลืออยากลงโปรแกรมเพิ่มอะไร ก็ไปหาได้ที่ https://chocolatey.org/packages เลย

ส่วนถ้าจะ update โปรแกรมก็แค่
choco update package
เช่น ถ้าต้องการ update JDK8 ให้เป็นตัวอัพเดทล่าสุดของรุ่น 8 ก็ใช้คำสั่ง
choco update jdk8

หรือถ้าจะ uninstall ก็ใช้
choco uninstall jdk8

ดูง่ายดี ลองไปทดลองใช้กันได้ครับ

Sunday, January 14, 2018

กำหนดภาษาแป้นพิมพ์ ให้กับ Raspbian แบบถาวร

ใครใช้ Raspbian (Jessie, Stretch) ก็อาจเจอเรื่องน่าหงุดหงิดก็คือ จะเปลี่ยนภาษาที่ใช้พิมพ์อย่างไร เพราะแป้นที่ถูกกำหนดมาแต่ต้นเป็น GB ซึ่งมีตำแหน่งบางตัวไม่ตรงกับแป้นพิมพ์ในบ้านเราซึ่งเป็น US/TH

ลองดูวิธีนี้ครับ

  • ให้คลิกขวาที่ Task Bar (แถบว่างๆด้านบนที่มี icon นั่นแหละครับ) แล้วเลือก Add / Remove Panel Items
  • ในแท็บ Panel Applets เลือกปุ่ม Add
  • เลือก Keyboard Layout Handler แล้วกด Add
  • จะปรากฎไอคอนเปลี่ยนภาษาที่มุมขวาสุด ซึ่งสามารถคลิกขวาแล้วไปเพิ่มลดภาษาของแป้นพิมพ์ได้ โดยการเลือก Keyboard Layout Handler Settings
  • ให้ tick Keep system layouts ออกก่อน จากนั้น Add ภาษาที่ต้องการได้เลย ถ้า Add ภาษาใหม่แล้วจะสามารถลบ GB ออกได้
  • คลิกกากบาทที่หน้าต่างเพื่อปิดเมนู ก็จะใช้งานภาษาได้
ปัญหาก็คือ เมื่อเรากำหนดภาษาเรียบร้อยแล้ว พอ reboot เสร็จ ทุกอย่างหายหมด กลับไปเป็นแป้น GB เหมือนเดิม (มันเป็น bug มาตั้งนานแล้ว เห็นคน report ไปเยอะแต่ก็ยังเป็นอยู่)

 มาดูวิธีแก้เพิ่มเติมตามนี้ ซึ่งผมสรุปคร่าวๆครับว่า
  • เลือก File Manager
  • กดเมนู View / Show Hidden
  • จะเห็น Folder ชื่อ .config ให้เข้าไปเรื่อยๆ ตามลำดับนี้คือ .config/lxpanel/LXDE-pi/panels
  • จะเจอไฟล์ชื่อ panel ให้ double click เปิดด้วย text editor
  • เลื่อนไปด้านล่างไฟล์ หา Plugin ที่มี type = xkb
  • ปรับแก้ตามนี้
Plugin {
type=xkb
Config {
   Model=pc105
   LayoutsList=us,th
   VariantsList=,
   ToggleOpt=grp:lwin_toggle
   KeepSysLayouts=0
}
 จากนั้นก็ save แล้ว reboot เพื่อดูผลครับ
หมายเหตุ:
grp:lwin_toggle คือกดแป้น Window ซ้ายบนแป้นพิมพ์เพื่อใช้เปลี่ยนภาษานะครับ ใครอยากใช้แป้นอื่นตรวจสอบได้ในหน้าต่างตอนเราเซ็ตแป้นพิมพ์ได้เลยครับ (ไม่มี accent grave, tilde หรือตัวหนอนนะครับ)

Wednesday, October 11, 2017

Markov โมเดล แบบบ้านๆ ตอนที่ 3 - Hidden Markov Models

ถ้าจะสรุปจากบทความก่อนหน้านี้ เราอาจพอบอกได้ว่า Markov model คือโมเดลรูปแบบหนึ่ง ที่ใช้พยากรณ์เหตุการณ์ใดๆ จากข้อมูลความน่าจะเป็นของเหตุการณ์ในอดีต โดยมีสมมติฐานว่า ความน่าจะเป็นของเหตุการณ์ใด จะขึ้นอยู่กับเหตุการณ์ก่อนหน้านั้นอย่างจำกัดเหตุการณ์ ซึ่งโดยทั่วไปจะสนใจเฉพาะเหตุการณ์ก่อนหน้าเพียงแค่เหตุการณ์เดียว ซึ่งเราเรียกว่า 1st order Markov assumption หรือสั้นๆ แค่ Markov assumption

แล้วอะไรคือ Hidden Markov Model (HMM) ล่ะ

ตามชื่อซึ่งมีคำว่า Hidden ก็หมายถึงว่า เราไม่ทราบเหตุการณ์ก่อนหน้าอย่างชัดเจน หรือการพยากรณ์ต้องใช้ปัจจัยอื่นมาเทียบเคียงด้วย

ก่อนหน้านี้ หากเราจะพยากรณ์สภาพอากาศที่ยังไม่เกิดขึ้น เราจะต้องทราบถึงสภาพอากาศในอดีตก่อน
แต่ถ้าเราไม่รู้ข้อมูลในอดีต หรือข้อมูลดังกล่าวถูกปกปิดไว้ (Hidden) จะคาดการณ์ได้อย่างไร

HMM เสนอว่า แม้ว่าเราจะไม่รู้ว่าเหตุการณ์ในอดีตเป็นอย่างไร (แต่ต้องรู้เหตุการณ์เริ่มต้น) ถ้าเราพอทราบเหตุการณ์ที่เกี่ยวเนื่องกัน ก็อาจเทียบเคียงเพื่อใช้พยากรณ์ได้

ตัวอย่างเช่น
สมมติว่าเราถูกขังไว้ในห้อง โดยไม่รู้สภาพอากาศจริง แต่ทราบว่ามีความสัมพันธ์ระหว่างสภาพอากาศกับการใช้ร่มของคนที่มาเยี่ยมเราในทุกๆวัน เช่น

ถ้าสภาพอากาศมีแดด ฝน และ หมอก โอกาสที่คนมาเยี่ยมจะพกร่มจะเป็น 0.1, 0.8 และ 0.3 ตามลำดับ และโอกาสที่คนมาเยี่ยมจะพกร่ม (โดยไม่สนใจสภาพอากาศเลย) คือ 0.5

สมมติว่าวันที่เราถูกขังไว้ในห้องเป็นวันที่มีแดด วันต่อมาคนมาเยี่ยมพกร่มมาด้วย โอกาสที่ฝนจะตกวันนี้เป็นเท่าใด

สิ่งที่เราต้องการจะหาคือ P(w2=rainny | w1=sunny, u2 = true)
เมื่อ w1 และ w2 คือเหตุการณ์สภาพอากาศเมื่อวาน (วันแรก) และวันนี้ (วันที่สอง) ตามลำดับ
และ u2 คือเหตุการณ์ที่คนมาเยี่ยมจะพกร่มในวันนี้ (วันที่สอง)

สิ่งที่เรารู้คือ ความน่าจะเป็นของสภาพอากาศที่ต่อเนื่องกัน P(w2 | w1) และ ความน่าจะเป็นที่ผู้มาเยี่ยมจะพกร่มในสภาพอากาศต่างๆ P(u | w) และความน่าจะเป็นที่ผู้มาเยี่ยมจะพกร่มโดยไม่ขึ้นกับสภาพอากาศ P(u)

ดังนั้นจำเป็นต้องจัดรูปแบบความสัมพันธ์ใหม่ ให้อยู่ในรูปของสามค่านี้

ก่อนอื่น มาทบทวนความน่าจะเป็นแบบมีเงื่อนไขกันเล็กน้อย
P(A|B) = P(A,B) / P(B)
หรือ
P(A,B) = P(A|B) P(B) = P(B|A) P(A)

ดังนั้น จากที่เราต้องการหา P(w2=rainny | w1=sunny, u2 = true)  ผมขอเขียนง่ายๆว่า P(w2 | w1, u2) นะครับ

P(w2 | w1, u2) = P(w2, w1, u2) / P(w1, u2)
= P(w2,w1 | u2) P(u2) / [ P(w1 | u2) P(u2) ]
= P(w2,w1 | u2) / P(w1 | u2)

แต่เนื่องจากเหตุการณ์ w1 กับ u2 ไม่ขึ้นต่อกัน (คนละวัน) P(w1 | u2) = P(w1) ตอนนี้สิ่งที่เราต้องการหาเลยเหลือเป็น
= P(w2, w1  | u2) / P(w1)

แต่เราไม่สามารถหาค่านี้ได้ เพราะสิ่งที่เรารู้มันกลับกันคือ P(u|w) ดังนั้น
เราจะใช้ทฤษฎีของ Bayes ที่เอาไว้เปลี่ยนลำดับของความน่าจะเป็นแบบมีเงื่อนไข
P(A|B) = P(B|A) P(A) / P(B)

= P(w2, w1  | u2) / P(w1)
= P(u2 | w2,w1) P(w2, w1) / P(u2) / P(w1)

จาก Markov assumption เราสนใจเฉพาะข้อมูลสภาพอากาศวันล่าสุดเท่านั้น เลยจะได้ว่า P(u2 | w2,w1) มีค่าเป็น P(u2, w2) ความสัมพันธ์ใหม่ก็เลยเหลือ
= P(u2 | w2) P(w2, w1) / [P(u2) P(w1)]

จัดรูปต่ออีกหน่อย เพราะเหลือค่าที่ไม่รู้คือ P(w2, w1) และ P(w1) ซึ่งเรารู้ว่าค่า P(w2, w1)/P(w1) มีค่าเท่ากับ P(w2 | w1)

สุดท้ายจึงได้
= P(u2 | w2) P(w2 | w1) / P(u2)

ซึ่งเมื่อกลับไปเขียนเต็มๆ จะได้ว่า
= P(u2 = true | w2 = rainy) P(w2 = rainy | w1 = sunny) / P(u2 = true)
และแทนค่าจะได้เป็น
= 0.8 x 0.05 / 0.5
= 0.08

นั่นคือ ความน่าจะเป็นที่ฝนจะตกวันนี้ เมื่อวันนี้คนมาเยี่ยมพกร่ม และเมื่อวานเป็นวันมีแดด คือ 0.08

มันก็จะงงๆตรงความน่าจะเป็นหน่อยนะครับ

Tuesday, July 18, 2017

Markov โมเดล แบบบ้านๆ ตอนที่ 2 - 1st order Markov assumption

เราลองมาดูตัวอย่างจาก Reference เดิมเพิ่มเติมกันครับ

ตัวอย่างที่แล้ว เราคาดการณ์เหตุการณ์ที่สามและสอง จากเหตุการณ์ที่ 1

จะเป็นอย่างไร ถ้าเราจะคาดการณ์เหตุการณ์ใดๆ จากเหตุการณ์ตั้งต้น เช่น เหตุการณ์ที่สามจากเหตุการณ์ที่ 1 เลย

สมมติว่าเรายังใช้ความน่าจะเป็นจาก finite state automaton รูปนี้
ตัวอย่างที่ 2 ถ้าวันนี้มีหมอก จงหาความน่าจะเป็นที่ฝนจะตกในวันมะรืน

ก่อนอื่นลองพิจารณาดูก่อนว่า จะมีกี่หนทางที่จะเกิดเหตุการณ์นี้ได้ จากสภาพอากาศ
วันนี้ -> พรุ่งนี้ -> มะรืน
ก็จะเป็นไปได้สามรูปแบบคือ
1. หมอก -> หมอก -> ฝน
2. หมอก -> ฝน -> ฝน
3. หมอก -> แดด -> ฝน

นั่นคือ ความน่าจะเป็นที่โจทย์ถาม ก็คือผลรวมของความน่าจะเป็นในแต่ละช่องทาง

P(W_3 = rainy | W1 = foggy)
 = P(W3 = rainy, W2= foggy | W1 = foggy) + P(W3 = rainy, W2= rainy | W1 = foggy) + P(W3 = rainy, W2= sunny | W1 = foggy)

คล้ายๆตัวอย่างที่แล้ว โดยใช้การประมาณ Markov เรารู้ว่า
 P(W3 = rainy, W2= foggy | W1 = foggy)
=  P(W3 = rainy | W2= foggy , W1 = foggy) * P(W2 = foggy | W1= foggy)
=  P(W3 = rainy | W2= foggy) * P(W2 = foggy | W1= foggy)

ดังนั้น ย้อนกลับไปสมการก่อนหน้านี้ จึงได้ว่า
P(W3 = rainy | W1 = foggy)
=  P(W3 = rainy | W2= foggy) * P(W2 = foggy | W1= foggy) + P(W3 = rainy | W2= rainy) * P(W2 = rainy | W1= foggy) + P(W3 = rainy | W2= sunny) * P(W2 = sunny | W1= foggy)
= (0.3*0.5) + (0.6*0.3) + (0.05*0.2)
= 0.15 + 0.18 + 0.01
= 0.34