TensorFlow


Installing with native pip


pip or pip3 was probably installed on your system when you installed Python. To determine whether pip or pip3 is actually installed on your system, issue one of the following commands:

$ pip -V  # for Python 2.7
$ pip3 -V # for Python 3.n 

recommend pip or pip3 version 8.1 or higher in order to install TensorFlow

$ sudo easy_install --upgrade pip
$ sudo easy_install --upgrade six 

Install TensorFlow


1.Install TensorFlow by invoking one of the following commands:

$ pip install tensorflow      # Python 2.7; CPU support
$ pip3 install tensorflow     # Python 3.n; CPU support

2.(Optional.) If Step 1 failed, install the latest version of TensorFlow by issuing a command of the following format:

$ sudo pip  install --upgrade tfBinaryURL   # Python 2.7
$ sudo pip3 install --upgrade tfBinaryURL   # Python 3.n 

Clone the git repository


$ git clone https://github.com/googlecodelabs/tensorflow-for-poets-2
$ cd tensorflow-for-poets-2

Download the training images

$ curl http://download.tensorflow.org/example_images/flower_photos.tgz | tar xz -C tf_files
$ ls tf_files/flower_photos

The preceding command should display the following objects:

daisy/
dandelion/
roses/
sunflowers/
tulip/
LICENSE.txt

(Re)training the network


Configure your MobileNet

IMAGE_SIZE=224
ARCHITECTURE="mobilenet_0.50_${IMAGE_SIZE}"

Start TensorBoard

$ tensorboard --logdir tf_files/training_summaries &

if error!

$ pkill -f "tensorboard"

Run the training

$ python3 -m scripts.retrain \
  --bottleneck_dir=tf_files/bottlenecks \
  --how_many_training_steps=500 \
  --model_dir=tf_files/models/ \
  --summaries_dir=tf_files/training_summaries/"${ARCHITECTURE}" \
  --output_graph=tf_files/retrained_graph.pb \
  --output_labels=tf_files/retrained_labels.txt \
  --architecture="${ARCHITECTURE}" \
  --image_dir=tf_files/flower_photos

Using the Retrained Model


The retraining script writes data to the following two files:

tf_files/retrained_graph.pb, which contains a version of the selected network with a final layer retrained on your categories.
tf_files/retrained_labels.txt, which is a text file containing labels.

 

Classifying an image


Now, let’s run the script on this image of a daisy:

$ python -m scripts.label_image \
    --graph=tf_files/retrained_graph.pb  \
    --image=tf_files/flower_photos/daisy/21652746_cc379e0eea_m.jpg
  • Image File tf_files/flower_photos/daisy/21652746_cc379e0eea_m.jpg

 

Result


daisy (score = 0.99071)
sunflowers (score = 0.00595)
dandelion (score = 0.00252)
roses (score = 0.00049)
tulips (score = 0.00032)

Sphinx


To start CMU Sphinx with macOS

$ brew tap watsonbox/cmu-sphinx

You’ll see some warnings as these formulae conflict with those in the main reponitory, but that’s fine.

Install the libraries:

$ brew install --HEAD watsonbox/cmu-sphinx/cmu-sphinxbase
$ brew install --HEAD watsonbox/cmu-sphinx/cmu-sphinxtrain # optional
$ brew install --HEAD watsonbox/cmu-sphinx/cmu-pocketsphinx

You can test continuous recognition as follows:

$ pocketsphinx_continuous -inmic yes

ทดสอบหาคำจากไฟล์เสียง


โหลดไฟล์เสียงทดสอบได้จาก

https://github.com/cmusphinx/pocketsphinx

โดยไฟล์เสียงที่ใช้ทดสอบจะอยู่ใน

/test/data/cards

ทดสอบหาคำจากเสียงโดยใช้คำสั่ง (ทดสอบไฟล์ชื่อ 001.wav)

pocketsphinx_continuous -infile 001.wav

ผลลัพธ์ที่ได้จะแสดงคำที่ได้จากเสียงออกมา

 

หากต้องการหา Hot word listening จะทำได้โดยการเพิ่มโค้ดต่อท้ายด้วย

-keyphrase "your word" -kws_threshold 1e-20

ตัวอย่างโค้ดแบบเต็ม

pocketsphinx_continuous -infile file.wav -keyphrase "oh mighty computer" -kws_threshold 1e-20


อธิบายโค้ด

เราสั่งให้หาคำว่า “oh mighty computer” ในไฟล์เสียงชื่อ file.wav

 

ทดลองหาคำจากเสียงที่พูดผ่านไมค์


ทดอบการหาคำจากไมค์โดยการหาคำว่า Hello

pocketsphinx_continuous -inmic yes -keyphrase "hello" -kws_threshold 1e-20

ผลลัพธ์ที่ได้เมื่อพูดคำว่า Hello

 

ที่มา

https://github.com/cmusphinx/pocketsphinx-ruby
https://cmusphinx.github.io/wiki/faq/#q-how-to-implement-hot-word-listening

To start CMU Sphinx with Windows with VS2017


จำเป็นต้องสร้าง folder ตามโครงสร้าง ดังต่อไปนี้

    \sphinx
        \pocketsphinx
        \sphinxbase

Electron


Electron เป็นเครื่องมือที่นำมาใช้ในการพัฒนา Application แบบ Cross-platform ซึ่งสามารถพัฒนา Application ได้โดยใช้ JavaScript, HTML และ CSS ตัวอย่างโปรแกรมที่ใช้ Electron ในการพัฒนา เช่น Slack, Visual Studio for Mac, Atom Editor เป็นต้น

เริ่มต้นโปรเจค Electron


ไฟล์สำคัญสำหรับการเริ่มต้นนี้ มี 3 ไฟล์ คือ

  • index.html เป็นส่วน UI หลัก
  • main.js เป็นส่วนที่เกี่ยวข้องกับการสร้างหน้า Window ขึ้นมา
  • package.json เป็นไฟล์ Config สำหรับ Nodejs
Your-app/
  ├── package.json
  ├── main.js
  └── app/
       └── index.html

เริ่มต้นโดยการสร้างโฟลเดอร์โปรแกรมใหม่ จากนั้นสร้างไฟล์ package.json ขึ้นมาโดยใช้ Command Line และ run คำสั่ง

$ npm init

จากนั้นตั้งค่าไฟล์

<<<< package.json >>>>
{
  "name": "your-app",
  "version": "0.1.0",
  "main": "main.js",
  "scripts": {
    "start": "electron ."
  }
}

ติดตั้ง Electron ลงในโฟลเดอร์โปรแกรม

$ npm install --save-dev electron

ได้ผลลัพธ์ที่เพิ่มมาในไฟล์ package.json คือ

{
  ...
  "devDependencies": {
    "electron": "^2.0.7"
  }
}

จากนั้น ที่ไฟล์ main.js จะตั้งค่าให้สร้าง BrowserWindow ขึ้นมาใหม่ที่มีความกว้าง 800 px และสูง 600 px และให้โหลดไฟล์ index.html นั้นขึ้นมาแสดง

<<<< main.js >>>>
const {app, BrowserWindow} = require('electron')
  
  function createWindow () {
    // Create the browser window.
    win = new BrowserWindow({width: 800, height: 600})
  
    // and load the index.html of the app.
    win.loadURL('file://' + __dirname + '/app/index.html');
  }
  
  app.on('ready', createWindow)

สุดท้าย สร้างโฟลเดอร์ชื่อ app สำหรับใช้ในการเก็บไฟล์ และสร้างไฟล์ index.html​

<<<< index.html >>>>
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8">
    <title>Hello World!</title>
  </head>
  <body>
    <h1>Hello World!</h1>
    We are using node <script>document.write(process.versions.node)</script>,
    Chrome <script>document.write(process.versions.chrome)</script>,
    and Electron <script>document.write(process.versions.electron)</script>.
  </body>
</html>

หลังจากสร้างไฟล์ index.html, main.js และ package.json แล้ว ให้ลอง run คำสั่งนี้ในโฟลเดอร์โปรแกรม เพื่อทดลองแสดงโปรแกรมขึ้นมาได้

$ npm start

จะได้ผลลัพธ์

Application Distribution


เมื่อต้องการสร้างโปรแกรมนี้ให้ผู้อื่นสามารถนำไปติดตั้งได้โดยสะดวก สามารถทำได้โดยการ Packaging App นั้น ๆ และทำให้เป็นไฟล์ .dmg เพื่อให้ง่ายต่อการติดตั้งใช้งาน

Packaging Your App into a File


ในที่นี้ จะใช้ Tool electron-packager เพื่อแปลงให้ไฟล์สามารถใช้งานในแพลตฟอร์มต่าง ๆ ได้ (ไฟล์ .exe, .app, etc.)

$ npm install --save-dev electron-packager

เข้าไปเพิ่ม script ในไฟล์ package.json

"scripts": {
  ...
  "package": "electron-packager ./ SoundMachine --mac --electron-version 0.37.5 --out=./ --overwrite"
  ...
}

โดยค่าต่าง ๆ ใน script ที่ถูกเพิ่มเข้าไปคือ

"package": "electron-packager <location of project> <name of project> <platform> <electron version> <options>"

จากนั้น

$ npm run-script package

จะได้ผลลัพธ์

สามารถคลิกที่ไอคอน เพื่อลองใช้โปรแกรมที่สร้างขึ้นได้

 

Create .dmg file


เมื่อทำการ Packaging File แล้ว จะทำไฟล์ .dmg สำหรับติดตั้งบน Mac ซึ่งในที่นี้จะใช้สคริปจาก

$ git clone https://github.com/andreyvit/create-dmg
$ cd create-dmg
$ ./create-dmg \
     --volname "FirstElectron Installer" \
     --volicon "../FirstElectron-darwin-x64/FirstElectron.app/Contents/Resources/electron.icns" \
     --window-pos 200 120 \
     --window-size 800 400 \
     --icon-size 100 \
     --icon ../FirstElectron-darwin-x64/FirstElectron.app 200 190 \
  FirstElectron_Installer.dmg \
  ../FirstElectron-darwin-x64/FirstElectron.app

การใช้งานสามารถทำได้หลากหลาย เช่น การตั้งชื่อของไฟล์ เซ็ตไอคอน หรือสิ่งต่าง ๆ ได้มากมาย โดยให้ run คำสั่ง

$ create-dmg [options...] [output_name.dmg] [source_folder]

option ต่าง ๆ ดูได้จาก https://github.com/andreyvit/create-dmg

เมื่อเสร็จสิ้น จะได้ไฟล์ .dmg ที่ต้องการ อยู่ในโฟลเดอร์ของโปรเจค create-dmg

เมื่อคลิกที่ไฟล์ .dmg ผลลัพธ์ที่ได้คือ


ศึกษาเพิ่มเติมได้จาก
>> http://electron.atom.io
>> https://medium.com/developers-writing/building-a-desktop-application-with-electron-204203eeb658
>> https://github.com/andreyvit/create-dmg

InternReview


สวัสดีครับ ก่อนอื่นผมขอแนะนำตัวเองก่อนเลยละกันนะครับผมชื่อ อั๋น เพิ่งจบปี 3 คณะวิทยาศาสตร์ สาขาวิทยาการคอมพิวเตอร์ มหาวิทยาลัยแม่โจ้ จ.เชียงใหม่ ซึ่งหลังจากจบปีที่ 3 ก่อนจะขึ้นปีที่ 4 นั้นก็จะต้องผ่านการฝึกงานกับบริษัทก่อน 2 เดือน ผมเลยได้ยื่นสมัครฝึกงานไปกับบริษัทประมาณ 2-3 ที่ได้ แต่ที่แรกที่ติดต่อผมกลับมาคือ Banana Coding ที่นี่ นี่เองครับ ผมจำเหตุการณ์วันที่พี่เค้าติดต่อกลับมาวันนั้นได้เลย เป็นช่วงสาย อยู่ๆ ก็มีคนโทรศัพท์เข้ามา

ผม : ฮัลโหลครับ สวัสดีครับผม
!@#$ : สวัสดีครับ พี่โทรมาจากบริษัทบานาน่าโค๊ดดิ่งนะครับ ไม่ทราบว่าน้องยังสนใจที่จะฝึกงานบริษัทพี่อยู่รึเปล่าครับ
ด้วยความดีใจตอนนั้นผมรีบตอบกลับไปทันทีเลยว่า
ผม : ครับยังสนใจอยู่ครับ
!@#$ : ได้ครับผมเป็นอันยืนยันเน้อะ งั้นเจอกันเดือนเมษานะครับเดี๋ยวพี่จะส่งอีเมล์ให้เรื่องการเตรียมตัวต่าง ๆ
ผม : ได้ครับผม ขอบคุณมากครับ

หลังจากวางโทรศัพท์ไปเพิ่งมานั่งคิดได้ เดี๋ยวนะบริษัทนี้จำได้ว่าอยู่ไกล ไอ่เราก็ไม่แน่ใจเลยเปิดแผนที่ดู แม่เจ้า !!! 19 โล ไปกลับนี่ 38 โลเลยนะ โอ้โหหหห แย่ละ จะขับรถไหวไหมเนี่ย จะเช่าหอก็คงไม่คุ้มเพราะเราก็อยู่แค่ 2 เดือนมันไม่มีหรอกมั้งที่หอไหนจะประกันหอแค่ 2 เดือนออกได้เลย จะเอาเงินค่าประกันไปทิ้งก็ไม่น่าจะคุ้มอีก เรื่องเช่าหออยู่ใกล้ ๆ ก็ตัดไปได้เลย แถวนั้นเขตของ มช. ด้วยส่วนมากคนในบริษัทเขาน่าจะเป็นเด็ก มช. มีแต่คนเก่งๆทั้งนั้นแน่เลย ตอนนั้นคือแบบกลัวไปหมดคิดไปต่าง ๆ นา ๆ กดดันตัวเองมาก จนสุดท้ายแล้วเราก็ตัดสินใจว่า เอาว่ะ !! ไหน ๆ เราก็เลือกแล้วจะยังไงสุดท้ายแล้วเราจบเราก็ต้องทำงาน เราต้องเจออะไรอีกหลายอย่างอยู่ดี ถือว่าซ้อมละกันก่อนจะจบไปเจอของจริง หลังจากคิดไปต่าง ๆ นาแล้วสุดท้ายพอมาเจอเข้าให้จริง ๆ นี่เรียกได้ว่าคนละเรื่องเลย

เริ่มจากการฝึกงานในช่วงเดือนแรกจะเป็นการเข้า Bootcamp คือการปูพื้นฐานต่าง ๆ เพื่อให้พร้อมทำงานจริง โดยพี่ ๆ จะมีเนื้อหามาสอนทุกวันเป็นเวลา 1 เดือนเต็ม ยกตัวอย่างคร่าวๆก็คือ Git,Trello,HTML,CSS,Bootstrap,Ruby,Ruby On rails ,JavaScript,Typescipt, Angular 2 หรือแม้กระทั่งการเขียน Test โดยการสอนแต่ละหัวข้อก็จะมีการบ้านให้มาฝึกทำ เพื่อให้เข้าใจสิ่งที่เรียนในวันนั้น ๆ ได้ดียิ่งขึ้น แถมหัวข้อในแต่ละวันยังเปลี่ยนคนสอนด้วยนะทำให้เป็นการทำความรู้จักกับพี่ ๆ ไปในตัว

หลังจากที่ผ่าน Bootcamp แล้วจะเป็นการได้ร่วมทำ Project ต่าง ๆ ของบริษัทโดยจะมี Mentor หรือพี่เลี้ยงคอยดูแลเราหากเราติดปัญหาอะไร สามารถสอบถามพี่เค้าได้เลย ตอนแรกที่เราได้จับงานก็แบบ เอ่อออ เราจะทำงานเค้าพังไหมว๊า 5555 เราจะทำได้ไหมเนี่ย สุดท้ายก็ค่อย ๆ ผ่านมันไปได้ด้วยดี ด้วยความช่วยเหลือของพี่ๆ คอยแนะนำเวลาเราติดปัญหาอะไร

การมาฝึกงานของผมนั้นเหมือนเป็นการพิสูจน์อะไรหลาย ๆ อย่างในใจที่คิดเอาไว้ตอนแรกเลยก็ว่าได้ เริ่มแรกจากการเดินทาง 19 กิโลเมตรก็ไม่ได้ไกลแบบที่คิดเท่าไหร่ ขับไปกลับ 38 กิโลเมตรนี่ก็ไม่ได้โหดร้ายอะไรขนาดนั้น อย่างที่สองที่ว่า “แถวนั้นเขตของ มช. ด้วยคนในบริษัทเขาน่าจะเป็นเด็ก มช. มีแต่คนเก่งๆทั้งนั้นแน่เลย” อันนี้เรื่องจริงแหะ มีครั้งนึงได้งานมาให้เขียนฟังก์ชั่นมาเพื่อดักสิ่งที่ลูกค้าเขาไม่ต้องการ ไอ่เราก็นั่งทำ ๆไป พอเสร็จเอาไปส่งให้พี่เค้าดูเพื่อรีวิวโค๊ด เชื่อไหมฮะฟังก์ชั่นที่ผมทำพี่แกย่อให้เหลือแค่บรรทัดเดียวเองแถมยังทำงานได้เหมือนเดิมอีกต่างหาก เค้าเก่งกันจริง ๆ แต่เค้าไม่ได้แค่เก่งอย่างเดียวนะครับ พี่เค้าทุกคนที่นี่เฟลนลี่เข้าหาง่าย สงสัยอะไรสามารถถามหรือคุยกันได้ทุกเรื่องเลย ไม่ว่าจะเป็นเรื่องโปรแกรม หรืออะไรต่าง ๆ นู่นนั่นนี่ ปรึกษาการลงทุนบิทคอยยังได้เลย 5555 คือคุยได้ทุกอย่างจริง ๆ ทำให้บรรยากาศในการทำงานไม่ได้ตึงเครียดเลยดูเป็นกันเองสุด ๆ

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

การทำ Android Application ภายใน 24 ชั่วโมง


การทำ Android application ภายใน 24 ชั่วโมง ที่ว่านี้ต้องบอกก่อนว่าไม่ได้เป็นการอดหลับอดนอนเพื่อมาทำแอปให้เสร็จภายใน 24 ชั่วโมงนะ แต่คือเราได้ทำแอปนี้ 3 วันวันละ 8 ชั่วโมงนั่นเอง โดยทีมของผมมีกันถึง 2 คน และก่อนจะทำแอปพลิเคชันขึ้นมา ก็มาคุยไอเดีย แนวคิดกันก่อนว่าจะทำแอปอะไร แอปแบบไหน และมีสโคปงานขนาดไหน ที่จำสามารถทำได้ในเวลาที่เหลือ

และต้องขอบอกอีกอย่างคือทีมของเรานี้ก็ไม่ได้ถึงขั้นระดับมือโปรที่รู้และจำได้ทุกอย่างเกี่ยวกับการเขียน Android แม้แต่ Syntax ของ Java ยังจำไม่ได้หมดเลย แต่ก็อาศัยการค้นหาเพิ่มเติมนี่แหละ อยากได้อะไรก็หา หรือบางฟังก์ชันที่เค้าเขียนมาแล้วมันโอเคก็ไปก็อบมาเลย หรือจะหา lib ต่างๆ มาช่วยก็ได้เช่นกัน

พอคุยๆ กันก็มีไอเดียเป็นแอปพลิเคชันที่เกี่ยวกับการ Generate Password ซึ่งแนวคิดนี้ก็เกิดจากการที่มีการคิดรหัสผ่านไม่ออก และสุ่มไปมั่วๆ พอถ้าเราสุ่มมั่วๆเอง ไม่นานเดี๋ยวก็ลืม หรือถ้า Generate Password มาก็อาจจะลืมได้เช่นกัน ก็เลยได้เพิ่มฟีเจอร์การจัดการรหัสผ่านมา เพื่อที่จะสามารถเก็บรหัสผ่าน ที่เราสุ่มขึ้นมาได้ทันที

หลังจากที่ได้มีการสรุปไอเดีย  และสโคป ต่างๆของตัวแอปเรียบร้อย ก็ทำการออกแบบคร่าวๆ ของโฟลการทำงาน และหน้าตาของแอป ด้วยกระดาษ กับปากกา นี่แหละเพียงเท่านี้ก็หมดแล้วสำหรับ 8 ชั่วโมงแรก

สรุปงาน 8 ชั่วโมงแรก

คือการสร้างแอปพลิเคชันตัวนึงเกี่ยวกับการสุ่มและจัดการรหัสผ่าน โดยมีฟีเจอร์ดังนี้คือ

  • สุ่มรหัสผ่าน
  • จัดการรหัสผ่าน (เพิ่ม, ลบ, แก้ไข)
  • มีการล็อกก่อนเข้าแอปพลิเคชัน
  • เปลี่ยนรหัสผ่านหน้าล็อกแอป

และได้ออกแบบ UI ร่างไว้ในกระดาษคร่าวๆ

.

.

.

วันต่อมาก็ได้เริ่มสร้างแอปพลิเคชันแล้วเย้! ซึ่งมีชื่อว่า IPassword จากนั้นก็อัพขึ้น BitBucket และแบ่งงานกับทีมโดยวันนี้จะเป็นการเขียนโค้ดทั้งหมด

ซึ่งเวลาเหลืออีก 16 ชั่วโมง จึงใช้ฐานข้อมูลภายในเครื่องของ Android เลยเพื่อที่จะเก็บข้อมูลรหัสผ่านต่างๆ  โดยเทคโนโลยีที่ใช้มีดังนี้

  • Java – เป็นภาษาที่ใช้ในการพัฒนา
  • SQLite – เป็น DBMS ที่ใช้ในการติดต่อกับฐานข้อมูล ซึ่งในการพัฒนา Android จะใช้เป็นตัวนี้อยู่แล้ว

สรุปงาน 8 ชั่วโมงที่สอง

ก็มีฟีเจอร์ที่เสร็จแล้วดังนี้คือ

  • สุ่มรหัสผ่าน
  • การเพิ่มรหัสผ่าน
  • การลบรหัสผ่าน
  • การล็อกก่อนเข้าแอปพลิเคชัน

             

.

.

.

พอถึงวันสุดท้าย ก็ทำฟีเจอร์ที่เหลือ เก็บรายละเอียดต่างๆ ติดโฆษณา แล้วเตรียมอัพขึ้น Play Store เลย!! และฟีเจอร์ที่จะทำวันนี้เหลือไม่มาก จึง Setup ต่างๆเตรียมพร้อมที่จะอัพของ Play store และออกแบบต่างๆ เช่น ไอคอนแอป และกราฟฟิกแอป เพราะต้องใช้ในการ อัพขึ้น Play Store ส่วนโปรแกรมที่ใช้ก็เป็น Photoshop นี่แหละ

ภาพต่างๆที่ใช้ในการอัพขึ้น Play store

  • ภาพหน้าจอ (อันนี้ Capture จากโทรศัพท์มาได้เลย)
  • ไอคอนขนาด 512×512
  • ภาพกราฟฟิค ขนาด 1024×500

ก่อนจะอัพขึ้นได้เนี่ยก็ต้องสมัครเป็น Android Developer ก่อนเนาะ และถ้าจะติดโฆษณาก็สมัคร Admob อีกอันนึง

เพียงเท่านี้ก็ได้ แอปพลิเคชันของเราวางอยู่บน Play strore แล้ว อ้อแต่ตอนอัพต้องรอการตรวจสอบก่อนประมาณ 10 – 30 นาทีได้

สรุปงาน 8 ชั่วโมงสุดท้าย

  • ทำฟีเจอร์ที่เหลือ
    • แก้ไขรหัสผ่าน
    • เปลี่ยนรหัสผ่านหน้าล็อกแอป
  • ทำหน้า About us เพิ่ม
  • ติดโฆษณา
  • เตรียมข้อมูลผลิตภัณฑ์ใน Store และ อัพขึ้น Play store

   

 

นี่แหละคือการทำ Android Application ภายใน 24 ชั่วโมง ที่เริ่มตั้งแต่ยังไม่มีไอเดียจนมาเป็นแอปพลิเคชันตัวนึงที่วางอยู่ใน Play Store ได้เนี่ยไม่ได้ยากอย่างที่คิดใช่มั้ยหล่ะครับ แต่แอปพลิเคชันนี้ก็ยังต้องการการพัฒนาต่อ ให้มันดียิ่งขึ้นไปอีกในภายหลัง แต่ก็แสดงให้เห็นว่า ภายในเวลา 24 ชั่วโมงนี้ก็สามารถที่จะทำแอปพลิชั่นเล็กๆ ให้สำเร็จได้นั่นเองครับผมมม

การวิเคราะห์ data จาก facebook เบื้องต้น


การจะทราบถึงปรากฏการณ์ทางสังคมว่าคนในสังคมกำลังสนใจสิ่งเหล่านี้มากน้อยแค่ไหน ทางหนึ่งก็ทำได้จากการวิเคราะห์ปริมาณการปฏิสัมพันธ์ของผู้คนบนสื่อสังคมออนไลน์

ในที่นี้จะกล่าวถึงการเก็บรวบรวมข้อมูลจาก page ของ Facebook และการนำข้อมูลมาวิเคราะห์เบื้องต้น

Facebook นั้นมีบริการที่เรียกว่า graph API ซึ่งเปิดให้ผู้ใช้สามารถดึงข้อมูลต่างๆมาเท่าที่ได้รับอนุญาตได้

การจะดึงข้อมูลนั้นต้องมี access token ซึ่งในเบื้องต้นสามารถได้มาจาก Graph Api Explorer

การดึงข้อมูลจาก Graph API Explorer

กดปุ่ม Get token แล้วระบบจะ generate access token ชั่วคราวมาให้ โดย token นี้จะมีอายุเพียง 1 วันเท่านั้น ถ้า expire ก็กดขอใหม่

นอกจากนี้ Graph Api Explorer ยังเปิดให้ทดลองดึงข้อมูลได้ เช่นในช่อง input ขนาดนี้เป็น /me?fields=id, nameเมื่อกดปุ่ม Submit ระบบก็จะส่ง id และ name ของ Login Facebook ที่ใช้งานอยู่มาให้

แต่การจะทราบถึงกระแสสังคมต่อเรื่องต่างๆนั้น ย่อมเป็นการดีกว่าที่จะดูจากจุดที่เป็นศูนย์รวมต่อเรื่องต่าง นั่นคือ page

ในที่นี้จะแสดงการดึงข้อมูลจาก page official ของ Maysa BNK48  เพราะคนเขียนชอบ

อยากแรกที่ต้องให้เลยคือ url name ของ page นั่นคือสิ่งที่ตามหลัง facebook.com/ ใน url ของ page นั่นเอง ในที่นี้คือ bnk48official.maysa

เมื่อนำมาใส่ใน Graph Api Explorer แล้ว submit ก็จะได้ชื่อและ id ของ page มาดังนี้

ถ้ารู้ id ของ page แล้วก็สามารถใช้ id ของ page (224218921376880) มาใส่แทน “bnk48official.maysa” ก็ query ข้อมูลมาได้เหมือนกัน

เติม /feed หลัง url เพื่อ query feed ต่างๆของ page มา

นอกจากนี้เรายังสามารถกำหนด field ที่ Api return กลับมาให้ได้ด้วย โดยใส่ที่ช่องด้านซ้าย หรือเติมท้าย url

โดยที่แสดงในรูปคือมี create_time, comment, รูปภาพใน post, จำนวนการแชร์ และประเภทของ post

ส่วน reaction ใน post นั้น tricky เล็กน้อย คือหากใส่ reactions ไปใน field ตรงๆเลยจะไม่มีข้อมูลมา ต้องเพิ่ม parameters ตามหลังด้วย

reactions.type(LIKE).limit(0).summary(1).as(like)

reactions.type(WOW).limit(0).summary(1).as(wow)

reactions.type(SAD).limit(0).summary(1).as(sad)

reactions.type(LOVE).limit(0).summary(1).as(love)

reactions.type(HAHA).limit(0).summary(1).as(haha)

reactions.type(ANGRY).limit(0).summary(1).as(angry)

comment ในโพสเองก็สามารถดึงได้ และ comment ใน comment หรือที่เรียกว่า reply ก็ดึงมาได้เช่นกัน

reaction ใน comment ก็ดึงมาได้ด้วยวิธีเดียวกับของโพส

ใน data ที่ return กลับมานั้น reply จะเป็น comment ที่ nested อยู่ใน comment อีกที

อย่างไรก็ตาม ในการ query 1 ครั้ง จะได้ข้อมูลมาเพียงบางส่วนเท่านั้น ลองเลื่อนช่อง output ดูด้านล่าง post สุดท้ายที่เห็นคือ 2018-01-14

post ที่เก่ากว่านี้จะอยู่อีกหน้าหนึ่ง และ query มาได้โดยใช้ string ในส่วนของ paging ในท้ายของข้อมูล

หรือก็คือเติม parameter after={string} ท้าย url นั่นเอง

หากกด link ตรง next ก็จะเป็นการ query ข้อมูลหน้าถัดไป

อย่างไรก็ดี จะมานั่งกดดูทีละหน้าก็ใช่ที่ ให้โปรแกรมเป็นคนทำงานให้ดีกว่า ในที่นี้จะแสดงตัวอย่างสคริป ruby ที่ใช้เก็บข้อมูล feed ในช่วงหกเดือนก่อนนี้ แล้วเก็บลง mongodb แต่เพื่อความรวบรัดจะขอละส่วนของ comment ไว้ก่อน

 

เก็บข้อมูลด้วย Ruby script

เหตุที่ใช้ mongodb เพราะสามารถโยน json เข้าไปได้เลย ไม่ต้องสร้าง schema ให้ยุ่งยาก

 

#!/usr/bin/env ruby

require 'json'
 require 'net/http'
 require 'mongo'

access_token = 'EAACEdEose0cBABAzbaZAnrr9F........
 page_name = 'bnk48official.maysa'

uri = URI("https://graph.facebook.com/v2.12/#{page_name}")
 fields = 'id,name,website,picture'
 params = { :access_token => access_token, :fields => fields }
 uri.query = URI.encode_www_form(params)
 res = Net::HTTP.get_response(uri)
 puts uri
 page = JSON.parse(res.body) if res.is_a?(Net::HTTPSuccess)
 puts page

 

สร้าง uri แล้วใช้ Net::HTTP ไป get respond มา

ส่วนของ feed จะใช้ uri นี้

reaction_str = 'reactions.type(LIKE).limit(0).summary(1).as(like),' +
 'reactions.type(WOW).limit(0).summary(1).as(wow),' +
 'reactions.type(SAD).limit(0).summary(1).as(sad),' +
 'reactions.type(LOVE).limit(0).summary(1).as(love),' +
 'reactions.type(HAHA).limit(0).summary(1).as(haha),' +
 'reactions.type(ANGRY).limit(0).summary(1).as(angry)'

uri = URI("https://graph.facebook.com/v2.12/#{page_name}/feed")
 feed_fields = "message,created_time,shares,#{reaction_str}"

params = { :access_token => access_token, :fields => feed_fields }
 uri.query = URI.encode_www_form(params)

res = Net::HTTP.get_response(uri)
 puts uri

ต่อ mongodb รอไว้ก่อน ในที่นี้ใช้ชื่อ db เป็น ‘fb_maysa’ และ collection เป็น ‘feed’

client = Mongo::Client.new([ config[‘mongodb_host’] ], :database => ‘fb_maysa’)
coll = client[:feed]

respond ที่ได้มานั้นจะเป็น json string ก็สามารถใช้ JSON.parse ได้เลย โดยแต่ละ post นั้นจะอยู่ใน key ‘data’

และเนื่องจากเราต้องการดึง feed มาเพียง 6 เดือนเท่านั้น เลยต้องมีการเทียบเวลาจาก field created_time ว่าเก่าเกิน 6 เดือนหรือไม่

ส่วนของ reactions นั้น จากตัวอย่างด้านบนจะเห็นว่า respond ส่วนนี้จะมี structure ที่ซับซ้อน จึงต้องแปลงให้อยู่ในรูปง่ายๆก่อน

แล้วใช้ collection.insert_one เพื่อ insert เข้า mongodb

r_j = JSON.parse(res.body)
 now = Time.now()
 r_j['data'].each do |f|

created_time = DateTime.strptime(f['created_time']).to_time
 time_diff = (now - created_time)
 month = 30*24*60*60
 pass_month = (time_diff/month).floor
 puts "passed month: #{pass_month}"

break if pass_month > 6

f['shares'] = f['shares']['count']

reaction_hash = {}
 ['like', 'wow', 'sad', 'angry', 'haha', 'love'].each do |r|
 count = f[r]['summary']['total_count']
 reaction_hash[r] = count
 f.delete r
 end
 f['reactions'] = reaction_hash

coll.insert_one(f)

end

อย่างที่กล่าวคือการ get_respond 1 ครั้งก็จะได้ข้อมูลมาเพียงบางส่วนเท่านั้น หากขะดึง feed ที่เก่ากว่านี้ก็ดึงได้จากส่วนของ paging

while r_j['paging']['next']
 uri = URI(r_j['paging']['next'])
 res = Net::HTTP.get_response(uri)
 puts uri

pass_month = 0

r_j = JSON.parse(res.body)
 r_j['data'].each do |f|

created_time = DateTime.strptime(f['created_time']).to_time
 time_diff = (now - created_time)
 month = 30*24*60*60
 pass_month = (time_diff/month).floor
 puts "passed month: #{pass_month}"

break if pass_month > 6

f['shares'] = f['shares']['count']

reaction_hash = {}
 ['like', 'wow', 'sad', 'angry', 'haha', 'love'].each do |r|
 count = f[r]['summary']['total_count']
 reaction_hash[r] = count
 f.delete r
 end
 f['reactions'] = reaction_hash

coll.insert_one(f)
 end

break if pass_month > 6
 end

เท่านี้ก็จะได้ feed ของ 6 เดือนย้อนหลังอยู่ใน database ของเราแล้ว จากนี้จะแสดงการนำข้อมูลมาสร้างกราฟง่ายๆโดยใช้ R

 

การใช้ R เพื่อวิเคราะห์ข้อมูล

ข้อมูลที่เป็นตัวเลขที่เราได้มาก็จะมี จำนวนการแชร์ และจำนวน reaction จึงจะใช้สองส่วนนี้เป็นหลัก

ขั้นแรกเลยก็คือโหลดข้อมูลจาก mongodb มาไว้ที่ R ก่อน

library(ggplot2)
 library(mongolite)
 library(chron)
 library(scales)

con <- mongo(collection = "feed", db = "fb_maysa", url = "mongodb://127.0.0.1",
 verbose = FALSE)
 mydata <- con$find()
 stat_data <- c()

dtparts <- t(as.data.frame(strsplit(mydata$created_time,'T')))
 row.names(dtparts) <- NULL
 dtparts[,2] <- sapply(dtparts[,2], function(x){
 xx <- strsplit(x, "\\+")
 return(xx[[1]][1])
 })

stat_data$time <- chron(dates=dtparts[,1],times=dtparts[,2], format=c('y-m-d','h:m:s'))

ส่วนของ Datetime นั้น R จะเห็นเป็นเพียง string จึงต้องปรับ format และแปลงให้อยู่ในรูปของ “chron” ซึ่งประกอบด้วย Date และ Time ให้  R เข้าใจก่อน

แล้วเรียงข้อมูลใหม่ จากวันที่ (stat_data$time)

stat_data$reaction <- mydata$reaction
 stat_data$reaction <- stat_data$reaction[order(stat_data$time, decreasing=FALSE),]

stat_data$shares <- mydata$shares
 stat_data$shares <- stat_data$shares[order(stat_data$time, decreasing=FALSE)]
 stat_data$comment_count <- stat_data$comment_count[order(stat_data$time, decreasing=FALSE)]
 stat_data$time <- stat_data$time[order(stat_data$time, decreasing=FALSE)]
 stat_data$sum_reactions <- rowSums(stat_data$reaction)

แปลง structure ของ data ให้เหมาะกับ ggplot2

d <- data.frame(stat_data$time, stat_data$shares, as.Date(stat_data$time))
 d <- cbind(d, "Shares")
 colnames(d) <- c('time', 'sums' ,'date', 'Total')
 d2 <- data.frame(stat_data$time, stat_data$sum_reactions, as.Date(stat_data$time))
 d2 <- cbind(d2, "Reaction")
 colnames(d2) <- c('time', 'sums' ,'date', 'Total')
 d <- rbind(d, d2)

month <- as.Date(cut(d$date, breaks = "month"))
 d <- cbind(d, month)

เพื่อให้ดูง่าย จึงควร plot graph โดยสรุปแต่ละเดือน เพื่อการนี้จึงเพิ่ม column month เข้ามา

จะได้ตารางหน้าตาแบบนี้

 

ผลลัพธ์

จำนวน share และ reaction ทั้งหมดของเพจในรอบ 6 เดือนจะมีดังนี้

“Total shares 8112”
“Total reactions 199453”

หากแยก reaction ตามประเภทก็จะได้ดังนี้

“Total like 152961”
“Total wow 1827”
“Total sad 466”
“Total angry 72”
“Total haha 8112”
“Total love 41394”

plot ด้วย ggplot2 โดยสรุปตามแต่ละเดือน

ggplot(data = d, aes(x=month, y=sums, group=Total)) +
 scale_color_manual(values=c("red", "blue")) +
 stat_summary(fun.y = sum, geom = "line", aes(color=Total)) +
 stat_summary(fun.y = sum, geom = "point", aes(color=Total)) +
 scale_x_date(labels = date_format("%Y-%m"), date_breaks = "1 month") +
 theme(legend.position="top")

ก็จะได้กราฟเส้น สีแดงคือจำนวนแชร์ สีน้ำเงินคือจำนวน reaction รวมๆ

 

Total reactions and shares in each month

จะเห็นว่ากราฟขึ้นสูงในเดือนธันวาคม นั่นคือช่วงที่มีดราม่าภาพหลุด และลดต่ำลงมาในเดือนมกราคม นั่นคือหลังจากถูกพักงานแล้ว

จากข้อมูลที่มีอาจจะ plot กราฟได้อีกหลายแบบ ลองเปรียบเทียบ reaction แต่ละแบบดู

 

Number of reactions by type per month

reaction ทั้งหมดจำนวนมากที่สุดก็คือ like นั่นเอง แต่ like ก็อาจจะตีความได้หลายความหมาย จึงอาจจะไม่มีประโยชน์เท่าไหร่นัก

ลอง plot อีกรูปโดยตัด like ออกไปดู

 

Number of reactions by type (exclude like) per month

เมื่อตัด like ออกไปแล้ว จำนวน reaction ที่มากที่สุดคือ love รองลงมาก็คือ haha

ทั้ง haha และ love เพิ่มขึ้นมาในช่วงเดือนธันวาคมซึ่งเป็นช่วงที่มีดราม่า แต่ angry ไม่ได้เพิ่มหรือลดอย่างเห็นได้ชัด  ก็อาจจะกล่าวสรุปจากตัวเลขได้ว่าคนไทยก็ไม่ได้โกรธขึ้งน้องจากกรณีดราม่าขนาดนั้น แต่ชอบหาความบันเทิงจากดราม่ามากกว่า

จบแล้วกับบทความนี้ จริงๆแล้วก็อาจจะต่อยอดได้อีกเช่นการพิจารณาข้อมูลของ comment และ reply ร่วมด้วย เนื่องจาก reaction ที่นำมาแสดงให้ดูเป็นเพียง reaction บนตัว post เท่านั้น ไม่ได้รวมถึง reaction ต่อ comment และ reply ด้วย ซึ่งหากนำมารวมด้วยแล้วก็อาจจะได้กราฟในรูปแบบที่ต่างออกไปก็ได้ อาจจะเจอ angry ในสัดส่วนที่มากขึ้นหรือเปล่า เพราะคนอาจจะแสดงความเกรี้ยวกราดลงใน  comment มากกว่าก็เป็นไปได้

 

 

วิธีการติดตั้ง Apache Spark ด้วย Docker


ในบทความนี้จะกล่างถึงใช้การสร้าง environment สำหรับทดสอบโปรแกรม Spark บน Hadoop โดยใช้ Docker

ก่อนจะเริ่มมาทำความรู้จักกับสิ่งที่ใช้ในบทความนี้ก่อนดีกว่า

Apache Spark

คือ Framework ในการเขียนโปรแกรมเพื่อประมวลผลแบบ MapReduced โดยเราเคยกล่าวถึงในบล็อค How to Installation Apache Spark with Cloudera VM ด้วย

Hadoop

คือ ซอฟท์แวร์ประเภท open source ที่จัดทำขึ้นเพื่อเป็นแพลตฟอร์มในการจัดเก็บข้อมูล ซึ่งมีกรอบการทำงานเพื่อใช้ในการจัดเก็บข้อมูลและประมวลผลข้อมูลที่มีขนาดใหญ่มากๆ ที่เราเรียกกันว่า Big Data

Docker

คือ engine ตัวหนึ่งที่มีการทำงานในลักษณะจำลองสภาพแวดล้อมขึ้นมาบนเครื่อง server เพื่อใช้ในการ run service ที่ต้องการ มีการทำงานคล้ายคลึงกับ Virtual Machine

ซึ่งตัว Docker Image ที่ใช้จะเป็น bananacoding/spark_hadoop

Read more  

วิธีการติดตั้ง Apache Spark ด้วย Cloudera VM


Apache Spark คือ Framework ในการเขียนโปรแกรมเพื่อประมวลผลแบบ MapReduce

ในบทความนี้จะกล่าวถึงการสร้าง environment สำหรับทดสอบโปรแกรม Spark โดยใช้ Cloudera Quickstart

Cloudera Quickstart คือ image ของ Virtual Machine โดยมีให้ทั้ง VirtualBox, VMWare และ Docker ในที่นี้จะแสดงการติดตั้งโดยใช้ Docker

Read more  

สร้างโมเดลพยากรณ์น้ำท่วม ด้วยภาษา R


ในภาวะที่อากาศเปลี่ยนแปลงบ่อย วันหนึ่งมี 3 ฤดูก็เป็นได้ เช้าหนาว บ่ายร้อน เย็นฝนตก กลางคืนตกหนักกว่าเดิม จนตอนเช้า อ้าวเห้ย!! ไม่เหมือนที่คุยกันไว้นี่หว่า!!  น้ำท่วมซะงั้น ซึ่งในหลายๆปีที่ผ่านมาก็ได้เกิดเหตุการณ์เช่นนี้บ่อยครั้ง ทั้งในประเทศและต่างประเทศ หน่วยงานหลายหน่วยงานก็ได้มีการแจ้งเตือนปริมาณน้ำฝนที่จะตกในแต่ละพื้นที่ มีการแจ้งเตือนให้ป้องกัน ให้หลีกเลี่ยงเส้นทางน้ำท่วมต่างๆ แต่ในบางครั้งเราก็ไม่ทันได้ทราบข่าวได้ติดตาม ฝนตกลงมาหนัก น้ำก็ท่วมละสิ (ถ้าไม่เรียกน้ำท่วมก็ เรียก น้ำรอการระบาย ก็ได้นะ 555+ ก็รอระบายออกจริงๆ หนิ )

ถ้าเราสามารถคาดการณ์ปริมาณน้ำที่จะท่วมได้ละ มันจะดีมั้ย ก็เรามีข้อมูลของปริมาณน้ำ และ ปริมาณน้ำฝน จากกรมอุตินิยมวิทยาบ้านเรานี่เอง แต่ไม่ใช่ว่าเรารู้ ข้อมูลเหล่านี้จะบอกได้เลยว่า วันนี้ฝนจะตกหนัก วันนี้น้ำจะท่วม เราต้องมีเครื่องมือเข้ามาช่วย นั้นคือ นั่นคือ นั่นคือ (ยัง ยัง จะเล่นอีก 555+) R แล้ว ​R คืออะไร ติดตั้งยังได้ มาเริ่มกันเลยดีกว่า

Read more  

How to develop Ruby on Rails with Windows 10’s Linux Subsystem


It has been quit sometimes that Windows developer don’t have an easy way to create Rails application. The most common way is to install Linux Virtual Machine or Docker. In a latest update of Windows 10, It has a new feature called “Windows Subsystem for Linux”. Underneath of this subsystem is Ubuntu Linux. In this article, I will guide you to create the Rails application based on Windows Subsystem for Linux.

Read more