ทำให้งาน Data Science ง่ายขึ้นด้วย (Nvidia) Docker!

How to

สำหรับคนที่ทำงานด้านการพัฒนา software คงพอจะรู้กันว่าปัญหา dependency management เป็นปัญหาที่เราต้องเจอกันบ่อยและเปลืองเวลาในการจัดการมากๆ เริ่มตั้งแต่การติดตั้ง development environment เพื่อใช้พัฒนาซอฟต์แวร์บนเครื่องตัวเอง บนเครื่องอื่นๆ ของสมาชิกในทีม ไปจนถึงการนำไปติดตั้งเพื่อใช้งานจริงบน production environment

งานสาย data science ก็เจอปัญหานี้ไม่ได้แตกต่างไปจากสายพัฒนา software อื่นๆ มากเท่าไหร่ โดยเฉพาะงาน deep learning ที่มี dependencies ค่อนข้างเยอะ ซึ่งถ้าใครเคยติดตั้ง Caffe ก็น่าจะพอเห็นภาพว่า เราต้องติดตั้ง libraries และ drivers หลายตัวหลายขั้นตอนกว่าที่ระบบจะพร้อมเริ่มงานได้จริงๆ ซึ่งก็มีปัจจัยหลายๆ อย่างที่พร้อมจะทำให้มันพังอยู่ตลอด และถึงแม้ว่าเราทำบนเครื่องตัวเองสำเร็จ คำถามต่อมาก็คือ.. เราจะเอาไปทำซ้ำที่เครื่องอื่นได้เหมือนกันรึเปล่า?

เอาเฉพาะแค่ environment ของ python เองก็ซับซ้อนมากแล้ว (https://xkcd.com/1987/)

ยกตัวอย่างสถานการณ์ที่เราน่าจะเจอกันบ่อยๆ สมมติเราเลือกใช้ภาษา python สำหรับการทำ deep learning แล้วกันนะครับ มีหลายเหตุหลายปัจจัยมากๆ ที่ทำให้โปรแกรมของเราทำงานไม่ได้หรือทำงานได้ผลลัพธ์ไม่เหมือนกัน ยกตัวอย่างเช่น

  • เราติดตั้งบน OS อะไร? (Windows, MacOS, Ubuntu, CentOS, ฯลฯ)
  • เราติดตั้ง python ยังไง? (brew, apt, conda, pipenv, ฯลฯ)
  • ใช้ python เวอร์ชันอะไร? (2.7, 3.6)
  • ใช้ package manager ตัวไหน? (pip, conda, easy_install, ฯลฯ)
  • รันด้วย CPU หรือ GPU?
  • เวอร์ชันของ dependency?
  • เวอร์ชันของ dependency ของ dependency?
  • dependency อื่นๆ นอกเหนือจากของ python อีก (CUDA, CuDNN, Graphic drivers, cmake, ฯลฯ)
  • สารพันปัญหาอื่นๆ

วันนี้เลยอยากมาพูดคุยเกี่ยวกับการใช้งาน Docker เบื้องต้น ว่าจะช่วยเราจัดการเรื่องพวกนี้ให้เป็นเรื่องง่ายขึ้นได้ยังไงบ้าง (สำหรับคนที่คุ้นเคยกับ Docker อยู่แล้ว สามารถข้ามไปอ่านในส่วนของ nvidia-docker เพื่อใช้งาน container กับ GPUs ได้เลยครับ)

Docker คืออะไร?

Docker เป็นเครื่องมือที่ช่วยเราในการสร้าง Software Container ครับ ลองจินตนาการว่ามันจะดีแค่ไหน ถ้าเราสามารถห่อโค้ดของเราพร้อมกับ dependencies ทั้งหมดที่จำเป็นต้องใช้รันโค้ดชุดนั้น เรียงใส่เข้าไปในตู้คอนเทนเนอร์(container) เรียกได้ว่าตู้นี้มีของทุกอย่างที่เราต้องการพร้อมเสร็จสรรพ และทุกครั้งที่เราอยากจะรันหรือใช้งานโค้ดชุดนั้น เราก็แค่ยกเอาตู้คอนเทนเนอร์นี้ออกมาวางไว้แล้วเรียกใช้งานโค้ดของเราได้เลย โค้ดของเราก็จะทำงานได้ปกติไม่ผิดเพี้ยนไปจากเดิม ไม่เกี่ยงว่าจะใช้ระบบปฏิบัติการอะไร สภาพแวดล้อมเป็นยังไง หรือจะตั้งอยู่ที่ไหนก็ตาม โคตรเทพ!

เปรียบเทียบว่า code และ dependencies ต่างๆ เป็นเฟอร์นิเจอร์ในบ้าน ถ้าเราติดตั้งจนมันใช้งานได้ครั้งนึงแล้ว ไม่ว่าเราจะยกตู้คอนเทนเนอร์ไปไว้ที่ไหน เราก็สามารถใช้งานมันได้เหมือนเดิมเสมอ http://www.elementspaceinc.net/project/single-unit-modular-homes

นอกจากนั้นเจ้าเครื่องมือที่ชื่อว่า Docker เนี่ย สามารถช่วยเราจัดการเกี่ยวกับคอนเทนเนอร์ในด้านต่างๆ ได้อีก เริ่มตั้งแต่การออกแบบพิมพ์เขียว(image)ของตู้คอนเทนเนอร์ การสร้างคอนเทนเนอร์จากพิมพ์เขียวนั้น การเรียกใช้งานคอนเทนเนอร์ รวมไปถึงการฝากการแชร์พิมเขียวพวกนั้นด้วย

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

Docker กับงาน Data science

แล้วหลังจากที่เราแพ็คของทุกอย่าง(scripts, notebooks, application, compilers, libraries, drivers และของทุกอย่างที่สามารถติดตั้งบนเซิร์ฟเวอร์ได้) เข้าไปอยู่ในคอนเทนเนอร์ได้แล้ว มันจะช่วยอะไรพวกเราได้บ้าง?

1. เตรียมพร้อม ติดตั้งเครื่องและเริ่มทำงานได้ง่ายและรวดเร็วกว่าเดิม

พอกันทีกับนั่งอ่าน tutorial ยาวหลายหน้า ติดตั้งเหล่าไดรเวอร์คอมไพเลอร์ไลบรารี่ต่างๆ อีกหลายสิบขั้นตอน เลิกเสียเวลาเป็นวันกับการงมหาว่าเราทำผิดขั้นตอนไหนทำไมมันถึงไม่เวิร์ค ด้วยการเรียกใช้งานคอนเทนเนอร์แทน ซึ่งใช้เวลาเพียงไม่กี่นาทีเท่านั้น ยิ่งถ้าเราใช้งานไลบรารี่ที่ค่อนข้างเป็นที่นิยมอย่าง caffe, tensorflow หรือ keras ส่วนใหญ่จะมีคนสร้างและแชร์ docker image ไว้อยู่แล้ว ซึ่งเราสามารถหยิบใช้งาน image พวกนี้ได้ทันทีโดยที่เราแทบไม่ต้องเซ็ทอัพอะไรเองเลยด้วยซ้ำ!

2. ทำซ้ำได้ง่าย (Reproducible)

เพื่อนๆ ในทีมของเราสามารถรันโค้ดของเราได้ และได้ผลลัพธ์เหมือนกันไม่ว่าจะบนเครื่องไหนๆ โดยไม่ต้องกังวลว่าเครื่องนั้นจะใช้ระบบปฏิบัติการอะไร หรือใช้ library เวอร์ชันอะไร ทำให้เราประหยัดเวลาของทีมในการ onboarding โปรเจกต์นั้นได้มาก

3. แชร์แอพของเราขึ้น production อย่างมั่นใจ

หลายครั้งที่ผลงานของเราจะอยู่ในรูปแบบ prediction model ซึ่งจะเป็นประโยชน์ก็ต่อเมื่อเราสร้างแอพพลิเคชันเพื่อให้คนอื่นสามารถเรียกใช้งานโมเดลของเราได้ Docker container ช่วยให้แอพที่เราสร้างขึ้นถูกนำขึ้นไปติดตั้งบน production server ได้ง่าย ไม่ว่าจะขึ้น dedicated server หรือ cloud service provider อย่าง AWS หรือ Google Cloud ก็ตาม ซึ่งก็เป็นผลดีทั้งกับทีม data science เอง แถมยังช่วยลดภาระของทีม dev และ devops ในการ deploy แอพของเราได้อีกด้วย

องค์ประกอบหลักที่ต้องรู้ก่อนใช้งาน Docker

1. Docker Image

เรียกได้ว่าเป็นพิมพ์เขียว หรือเป็นต้นแบบของการสร้าง container ขึ้นมาใช้งาน ถ้าเปรียบเทียบกับการเขียนโปรแกรมเชิงวัตถุ(OOP) เจ้าตัว docker image นี้ก็เปรียบเสมือน class ซึ่งเป็นต้นแบบในการสร้าง object (docker container) อีกทีครับ

Docker image สามารถเรียกใช้ได้สองวิธี นั่นก็คือการสร้างจาก Dockerfile ที่เป็นสคริปต์ที่อธิบายว่าเราจะติดตั้งอะไรลงไปใน image บ้าง หรือดาวน์โหลดและเรียกใช้งาน docker image ที่มีอยู่แล้วบนอินเตอร์เน็ต

2. Docker Container

สร้างมาจาก docker image ซึ่งเป็นส่วนที่จะถูกนำไปใช้งานและโค้ดจะถูกรันจริงๆ ที่ส่วนนี้ ซึ่งแสดงให้ดูได้ตามรูปด้านล่าง

https://www.quora.com/What-is-the-maximum-size-of-a-docker-image-you-can-store-on-Docker

3. Docker Registry

นอกจากเราจะสร้าง docker image มาเพื่อใช้รันบนเครื่องตัวเองแล้ว เราสามารถอัพโหลดเข้าไปสู่ server กลางสักอันเพื่อที่จะเอาไปใช้งานบนเครื่องอื่นๆ ได้ด้วย โดย server ที่ว่านี้เราจะเรียกว่าเป็น docker registry

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

เริ่มต้นใช้งาน Docker (เบื้องต้น)

1. ติดตั้ง Docker

สามารถศึกษาคู่มือและทำการติดตั้งได้จาก https://docs.docker.com/install/ ถ้าหากติดตั้งสำเร็จแล้ว สามารถตรวจสอบว่ามันเวิร์คหรือไม่ด้วยคำสั่ง docker run hello-world ถ้าเจอข้อความคล้ายๆ ด้านล่างขึ้นแสดงว่าเราติดตั้งมันได้เรียบร้อยดีแล้ว เย่!

$ docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

2. สร้าง Docker image

ในบทความนี้จะพูดถึงสองวิธีหลักๆ ในการได้มาซึ่ง docker image ของเรา ซึ่งสามารถใช้วิธีการใดก็ได้

2.1 สร้าง docker image จาก Dockerfile

เราจะสร้าง docker image ด้วยการสร้างไฟล์ Dockerfile ซึ่งเป็นโพยที่ใช้อธิบายว่าจะรันคำสั่งอะไรหรือติดตั้ง software อะไรบ้าง เพื่อให้ docker ช่วยสร้าง image ให้เราตามนี้โดยอัตโนมัติ

  • FROM — ใช้บอกว่าเราจะเอา image ตัวไหนมาเป็นต้นแบบ
  • RUN — ใส่คำสั่งที่ต้องการให้ docker ทำขณะที่สร้าง image ขึ้นมา
  • WORKDIR — กำหนด directory ที่ docker container จะรันคำสั่งเมื่อมันทำงาน
  • CMD — หาก container ถูกเรียกใช้โดยไม่ระบุคำสั่ง มันจะรันคำสั่งนี้เสมอ

จากนั้นรันคำสั่งด้านล่างเพื่อสร้าง docker image โดยตั้งชื่อว่า datawow/tensorflow

docker build -t datawow/tensorflow .

เพียงเท่านี้ docker image ก็จะถูกสร้างขึ้นในเครื่องคอมพิวเตอร์ของเราแล้ว ซึ่งสามารถตรวจสอบได้ด้วยคำสั่ง docker images ครับ

2.2 ดาวน์โหลด Pre-built docker image

นอกจากวิธีข้างต้น เราสามารถใช้จุดได้เปรียบอีกอย่างของการใช้ Docker คือเราสามารถดาวน์โหลด image ของคนอื่นมาใช้ได้เลย! ซึ่งอะไรที่คนเค้าฮิตใช้กันมักจะมีคนสร้าง image พวกนั้นไว้อยู่แล้ว โดยมี Dockerhub เป็น registry หลักที่เราไปเลือกหยิบ image มารันได้เลย และถ้าเราต้องการอ่านคำอธิบายหรือข้อมูลเพิ่มเติม ก็สามารถคลิกเข้าไปอ่านรายละเอียดของ image นั้นได้เหมือนกันครับ

เว็บ Dockerhub เป็นศูนย์รวม docker image จากนักพัฒนาทั่วโลก https://hub.docker.com/

หลังจากที่เราไปเจอ image ที่ต้องการจะใช้ ยกตัวอย่างในเคสนี้คือ tensorflow/tensorflow เราสามารถใช้คำสั่งด้านล่างในการดาวน์โหลด docker image นั้นมาเตรียมใช้งานในเครื่องของเราเอง

$ docker pull tensorflow/tensorflow

หลังจากรันคำสั่ง docker pull จะมีหน้าแสดงสถานะการดาวน์โหลด image มาติดตั้งบนเครื่อง

3. ตรวจสอบว่ามี docker image อยู่บนเครื่องเราแล้ว

สามารถทำได้ด้วยคำสั่งด้านล่าง ซึ่งจะแสดงรายการ image ทั้งหมดที่มีในเครื่อง

$ docker images

ที่เน้นสีแดงคือ docker image ที่เราเพิ่งสร้างขึ้นเมื่อซักครู่

4. สร้างโฟลเดอร์และโค้ดที่ต้องการทำการรันทดสอบ

ก่อนอื่นเราจะสร้างโฟลเดอร์ ที่ชื่อว่า ~/dockertut เพื่อใช้สำหรับสาธิตการทำงาน และมีไฟล์ตัวอย่าง mnist_softmax.py อยู่ภายในโฟลเดอร์นั้น สามารถดาวน์โหลดได้จาก github ของ tensorflow ซึ่งใช้เพื่อ train linear classification model อย่างง่ายและแสดง test accuracy หลังจบการทำงาน

$ mkdir ~/dockertut
$ cd ~/dockertut
$ wget https://raw.githubusercontent.com/tensorflow/tensorflow/master/tensorflow/examples/tutorials/mnist/mnist_softmax.py

5. สร้างและรัน Docker container จาก Docker image

เมื่อเรามี docker image พร้อมที่จะเรียกใช้งานแล้ว ขั้นตอนนี้ก็เป็นส่วนที่น่าตื่นเต้นที่สุด นั่นคือการรัน docker container จาก image ที่สร้างขึ้นในขั้นตอนที่แล้วนั่นเอง (tensorflow/tensorflow) สามารถทำได้ด้วยคำสั่ง docker run ตามตัวอย่างด้านล่าง

$ docker run --volume $(pwd):/workspace tensorflow/tensorflow python /workspace/mnist_softmax.py

ซึ่งคำสั่งประกอบด้วยสามส่วนหลักๆ ดังนี้

  • Parameters — ใช้ใส่ configuration ได้หลายอย่าง ซึ่งในตัวอย่างนี้ใส่ volume เพื่อบอกว่า ให้เอาโฟลเดอร์ปัจจุบันบนเครื่อง host ( $(pwd) )แชร์ให้ container สามารถใช้ร่วมกันได้ที่ path: /workspace
  • Image name — เพื่อบอกว่าให้รันคำสั่งใน docker image ที่ชื่อว่าอะไร (tensorflow/tensorflow)
  • Command — บอกว่าให้รัน command อะไรเมื่อถูกเรียกใช้งาน ในที่นี้คือให้รัน script ที่เราใส่เค้าไปใน container ตาม path ที่กำหนด (python /workspace/mnist_softmax.py)

ผลลัพธ์จากการรันคำสั่งข้างต้น ตัวสคริปต์สามารถทำงานได้ตามปกติ ทั้งขั้นตอนการ training และแสดงผล testing accuracy ได้อย่างถูกต้องโดยที่เราไม่ต้องติดตั้ง dependency ต่างๆ ด้วยตัวเองเลย

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

ทำให้ containerใช้งาน GPU ได้ด้วย nvidia-docker

ปัญหาของ Docker คือมันไม่สามารถใช้งาน GPU driver ได้​ (อ้าว!) เพราะ docker container นั้นอำนวยความสะดวกเราด้วยการรันโค้ดบน environment พิเศษที่ไม่สนใจว่าจะมันจะตั้งอยู่บนแพล็ตฟอร์มหรือระบบปฏิบัติการไหนๆ แต่นั่นก็หมายความว่ามันก็ไม่สนใจฮาร์ดแวร์พิเศษอย่าง GPU ด้วยเหมือนกัน

แต่ขอแสดงความยินดีกับคนที่ใช้การ์ดจอจากค่าย Nvidia เรามีทางออกง่ายๆ มานำเสนอ นั่นก็คือการใช้ nvidia-docker นั่นเองครับ

nvidia-docker ช่วยให้ docker container สามารถเข้าถึง https://github.com/NVIDIA/nvidia-docker

nvidia-docker คือ wrapper ที่ห่อคำสั่งต่างๆ ของ docker อีกที สามารถทำคำสั่งได้ทุกอย่างที่ docker ทำได้แต่เพิ่มความสามารถในการเข้าถึง GPU เข้ามาด้วย ดังนั้นเราสามารถใช้ nvidia-docker แทนคำสั่ง docker ปกติได้เลยครับ ซึ่งแน่นอนว่าต้องทำการติดตั้งก่อนครับ

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

$ nvidia-docker run hello-world
Hello from Docker!
This message shows that your installation appears to be working correctly.
...

แล้วถ้าเรา pull pre-built image จาก Dockerhub ที่ติดตั้ง CUDA + Nvidia drivers มาแล้ว เราก็สามารถเรียกใช้งาน container ของเราที่มีการ์ดจอพร้อมใช้งานได้เลย สามารถทดสอบด้วย image ที่ชื่อ nvidia/cuda โดยการรันคำสั่ง nvidia-smi เพื่อเช็คว่าคอนเทนเนอร์ของเราเจอ GPU อย่างที่คาดไว้

หรือเราสามารถ train mnist dataset เหมือนในตัวอย่างที่แล้วก็ได้เหมือนกัน แตกต่างกันที่คราวนี้เราใช้ GPU และใช้เวลาน้อยกว่ามากๆ!

สรุป

  1. Docker ทำให้เราติดตั้ง environment สำหรับการทำงาน data science ได้ง่ายและเร็ว ด้วยการเขียน Dockerfile ใช้เอง หรือดาวน์โหลด image ของชาวบ้านมาใช้ก็ได้
  2. Docker ช่วยให้เราแชร์ environment ให้เพื่อนร่วมทีมง่ายและเร็วขึ้น ทำให้เรา reproduce ผลลัพธ์จากการทำ analysis บนเครื่องอื่นๆ ได้
  3. ทำให้การ deploy machine-learning application ทำได้ง่ายขึ้น
  4. nvidia-docker ช่วยให้เราใช้ docker แบบมี GPU ได้
  5. หากจะเอาไปใช้งานจริง จำเป็นต้องศึกษารายละเอียดการใช้งานเพิ่มเติม ซึ่งสามารถหาอ่านได้ที่ official guide ของ docker ครับ

สุดท้ายนี้ขอขอบคุณท่านผู้อ่านที่ยังติดตามมาจนถึงตอนจบนี้ได้นะครับ ยินดีน้อมรับทุกคำแนะนำติชม สามารถคอมเมนต์ไว้ได้เลยนะครับ :)

ส่งท้ายด้วยลิงค์ที่น่าสนใจ

Contact us

Drop us a line and we will get back to you