Category: Uncategorized

  • Google Instant Apps

    Android Instant Apps – Trải nghiệm mới về Ứng dụng Android

    Mở đầu

    Tại sự kiện I/O 2016, Google đã công bố một khái niệm hoàn toàn mới về ứng dụng Android. Đó là Android Instant App. Đúng như tên gọi thì Instant Apps là những ứng dụng có thể được sử dụng ngay cả khi không cần cài đặt. Cũng giống như lúc đi chợ, khi "lựa hành" trên CH Play chúng ta đều muốn kiểm tra, "lật qua lật lại" "món hàng" mình định mua. Instant App hỗ trợ người dùng có thể "test nhanh" ứng dụng rồi mới quyết định có muốn tải về hay không, thay vì bị lừa bởi hình ảnh, video intro rồi tải về và xóa ngay lập tức vì thất vọng.

    Bài viết hôm nay chúng ta sẽ tìm hiểu về Android Instant Apps.

    Instant App là gì và sự khác biệt với Normal App như thế nào ?

    • Như phần giới thiệu, bạn cũng đoán được Instant App là gì. Hiểu một cách đơn giản, Instant App là một ứng dụng native giúp cho người dùng có thể ngay lập tức sử dụng ứng dụng của các nhà phát triển mà không cần cài đặt. Để xây dựng ứng dụng như vậy, các nhà phát triển cần tạo ra các module riêng và tích hợp với deep link, sau đó người dùng có thể nhấp vào URL để dùng thử ứng dụng.
    • Instant App vẫn được tải về như các app bình thường khác nhưng thay vì ở lại trên điện thoại của bạn, nó làm việc giống như bạn truy cập một website và sau đó thoát ra, nó chỉ lưu ứng dụng đó tạm thời và được xóa ngay khi không còn sử dụng.
    • Tiết kiệm thời gian và bộ nhớ sử dụng khi không chiếm dụng tài nguyên thiết bị cũng như mất thời gian download (những ngày nghỉ mà đứt cáp thì bạn sẽ càng hiểu rõ sự khác biệt này)
    • Một ví dụ ưu điểm nữa là khi bạn phát triển một ứng dụng như Instagram hoặc Youtube, muốn chia sẻ với bạn bè thì với Instant App thích hợp, chỉ cần đơn giản gửi 1 link là họ có thể dễ dàng và cực kỳ nhanh chóng xem được mà không cần phải cài đặt ứng dụng.

    Ưu điểm của Instant App (Góc nhìn của lập trình viên)

    1. Tăng khả năng khám phá Instant App đủ điều kiện để được giới thiệu trên trang chủ của Google Play Games, có khả năng tiếp cận với người dùng.
    2. Nhiều người chơi hơn Nếu người dùng không phải lo lắng về vấn đề cài đặt, họ có nhiều khả năng sẽ tham gia vào trò chơi của bạn.
    3. Khả năng kiếm tiền Các dịch vụ mua hàng trong ứng dụng và quảng cáo được hỗ trợ
    4. Trải nghiệm chất lượng cao Mọi thứ hoạt động ngay khi người dùng ấn vào "Instant Play"

    Làm thế nào để sử dụng Instant App ?

    Phần giới thiệu, ưu điểm có vẻ cực kỳ hoành tráng, thời gian ra mắt cũng được 5 năm nhưng nhiều bạn sẽ thắc mắc là lướt CH Play mấy năm trời có thấy cái Instant App nào đâu ?! Là do các bạn chưa kích hoạt nó mà thôi !

    • Vào Setting, tìm đến các cài đặt cho Google và tìm đến Google Play Instant. Tại đây bạn kích hoạt nó lên là có thể sử dụng Instant App của Google. (Tùy mỗi dòng điện thoại sẽ có những cách bố trí mục cài đặt khác nhau nên mình không thể chỉ rõ step-by-step được)

    Vậy làm thế nào để tạo ra một Instant App ?

    Cuối cùng thì phần mà các lập trình viên hóng nhất cũng đến. Cùng tìm hiểu cách tạo một Instant App đơn giản nào !

    I. Permission

    Vì sự nhỏ gọn, tiện lợi, Instant App không thể thực thi tất cả những tác vụ mà một App bình thường có thể làm. Cụ thể, nó chỉ có thể sử dụng các permissions sau:

    • ACCESS_COARSE_LOCATION
    • ACCESS_FINE_LOCATION
    • ACCESS_NETWORK_STATE
    • BILLINGDeprecated as of Play Billing Library 1.0.
    • CAMERA
    • INSTANT_APP_FOREGROUND_SERVICEOnly in Android 8.0 (API level 26) and higher.
    • INTERNET
    • READ_PHONE_NUMBERSOnly in Android 8.0 (API level 26) and higher.
    • RECORD_AUDIO
    • VIBRATE
    • WAKE_LOCK

    Thêm vào đó, các Instant App cũng không thể :

    • Sử dụng background services
    • Send notifications khi chạy trên background

    II. Kết nối với các ứng dụng đã được cài đặt

    Khi phát triển một Instant App, hãy nhớ rằng chỉ có thể tương tác với các ứng dụng đã cài đặt trên thiết bị nếu thỏa mãn một trong các điều kiện sau :

    • Một hoặc nhiều Activity trong các ứng dụng đó được cài đặt android:android:visibleToInstantApps=true – chỉ có sẵn cho Android 8.0 (API 26) trở lên.
    • Ứng dụng đã cài đặt chứa intent filter bao gồm CATEGORY_BROWSABLE
    • Instant App đang gửi một Intent bằng ACTION_SEND, ACTION_SENDTO hoặc ACTION_SEND_MULTIPLE

    III. Cấu hình Project

    1. Thêm khai báo sau vào app module build.gradle :

      implementation("com.google.android.gms:play-services-instantapps:17.0.0")
      
    2. Update targetSandboxVersion :

      <manifest
          xmlns:android="http://schemas.android.com/apk/res/android"
          ...
          android:targetSandboxVersion="2" ...>
      
    3. Khai báo các module hỗ trợ Instant App

      • View > Tool Windows > Project
      • Ấn chuột phải vào module, chọn Refactor > Enable Instant Apps Support
      • Chọn module tại dropdown menu
      • OK Android Studio thêm khai báo sau vào manifest của module:
      <manifest ... xmlns:dist="http://schemas.android.com/apk/distribution">
          <dist:module dist:instant="true" />
          ...
      </manifest>
      
    4. Code bất cứ thứ gì có thể vào module bạn đã chọn

    5. Deploy Instant App

      • Nếu bạn đã cài đặt ứng dụng (với bất kỳ phiên bản nào) trên thiết bị, uninstall nó đi
      • Run > Run/Debug Configurations, kích hoạt Deploy as instant app
      • Run > Run hoặc ấn biểu tượng Run trên toolbar để chạy Instant App.

    Nếu bước 4 của bạn được "thuận buồm xuôi gió" một Instant App sẽ được hiển thị lên thiết bị của bạn. Hãy thử back ra home screen và tìm một vòng xem có app nào được cài đặt không nhé ! – Dĩ nhiên là không rồi.

    Kết thúc

    Trong tương lai gần, có thể nói Instant App là một bước tiến lớn đối với trải nghiệm người dùng. Khi mà tốc độ các kết nối ngày càng nhanh chóng và lưu trữ đám mây trở nên phổ biến; thì việc sử dụng một ứng dụng ngay lập tức và không cần cài đặt là một điều thực sự tuyệt vời.

    Trên đây là một vài giới thiệu tổng quan nhất về Instant App, cũng như tầm phát triển và ý nghĩa mà nó mang lại. Cảm ơn các bạn đã giành thời gian theo dõi.

    Bạn có thể tìm hiểu sâu hơn về Instant App, xây dựng một ứng dụng tại: Android Developer – Google Play Instant

  • Neighborhood-Based Collaborative Filtering – Recommendation Systems – Phần 2

    Neighborhood-Based Collaborative Filtering – Recommendation Systems – Phần 2

    Xin chào mọi người, ở bài viết trước thì mình đã giới thiệu qua về Hệ thống gợi ý ( Recommendation Systems ) và trong bài biết lần này mình sẽ trình bày với các bạn 1 phương pháp của Lọc cộng tác ( Collaborative Filtering ) có tên là Neighborhood-based Collaborative Filtering (NBCF)

    Nội dung trong phần này

    Giới thiệu

    Trong Content-based Recommendation Systems, chúng ta đã biết đặc điểm của Content-based Recommendation Systems là việc xây dựng mô hình cho mỗi user không phụ thuộc vào các users khác mà phụ thuộc vào profile của mỗi items. Việc làm này có lợi thế là tiết kiệm bộ nhớ và thời gian tính toán. Đồng thời, hệ thống có khả năng tận dụng các thông tin đặc trưng của mỗi item như được mô tả trong bản mô tả (description) của mỗi item. Bản mô tả này có thể được xây dựng bởi nhà cung cấp hoặc được thu thập bằng cách yêu cầu users gắn tags cho items. Việc xây dựng feature vector cho mỗi item thường bao gồm các kỹ thuật Xử lý ngôn ngữ tự nhiên (Natural Language Processing – NLP).

    Cách làm trên có hai nhược điểm cơ bản. Thứ nhất, khi xây dựng mô hình cho một user, các hệ thống Content-based không tận dụng được thông tin từ các users khác. Những thông tin này thường rất hữu ích vì hành vi mua hàng của các users thường được nhóm thành một vài nhóm đơn giản; nếu biết hành vi mua hàng của một vài users trong nhóm, hệ thống nên suy luận ra hành vi của những users còn lại. Thứ hai, không phải lúc nào chúng ta cũng có bản mô tả cho mỗi item. Việc yêu cầu users gắn tags còn khó khăn hơn vì không phải ai cũng sẵn sàng làm việc đó; hoặc có làm nhưng sẽ mang xu hướng cá nhân. Các thuật toán NLP cũng phức tạp hơn ở việc phải xử lý các từ gần nghĩa, viết tắt, sai chính tả, hoặc được viết ở các ngôn ngữ khác nhau.

    Những nhược điểm phía trên có thể được giải quyết bằng Collaborative Filtering (CF). Trong bài viết này, tôi sẽ trình bày tới các bạn một phương pháp CF có tên là Neighborhood-based Collaborative Filtering (NBCF). Bài tiếp theo sẽ trình bày về một phương pháp CF khác có tên Matrix Factorization Collaborative Filtering. Khi chỉ nói Collaborative Filtering, chúng ta sẽ ngầm hiểu rằng phương pháp được sử dụng là Neighborhood-based.

    Ý tưởng cơ bản của NBCF là xác định mức độ quan tâm của một user tới một item dựa trên các users khác gần giống với user này. Việc gần giống nhau giữa các users có thể được xác định thông qua mức độ quan tâm của các users này tới các items khác mà hệ thống đã biết. Ví dụ, A, B đều thích phim Cảnh sát hình sự, tức đều rate bộ phim này 5 sao. Ta đã biết A cũng thích Người phán xử, vậy nhiều khả năng B cũng thích bộ phim này.

    Các bạn có thể đã hình dung ra, hai câu hỏi quan trọng nhất trong một hệ thống Neighborhood-based Collaborative Filtering là:

    • Làm thế nào xác định được sự giống nhau giữa hai users?
    • Khi đã xác định được các users gần giống nhau (similar users) rồi, làm thế nào dự đoán được mức độ quan tâm của một user lên một item?

    Việc xác định mức độ quan tâm của mỗi user tới một item dựa trên mức độ quan tâm của similar users tới item đó còn được gọi là User-user collaborative filtering. Có một hướng tiếp cận khác được cho là làm việc hiệu quả hơn là Item-item collaborative filtering. Trong hướng tiếp cận này, thay vì xác định user similarities, hệ thống sẽ xác định item similarities. Từ đó, hệ thống gợi ý những items gần giống với những items mà user có mức độ quan tâm cao.

    Phương pháp này được chia thành 2 hướng nhỏ, là User-User Collaborative Filtering (uuCF) và Item-Item Collaborative Filtering (iiCF).

    uuCF : Về cơ bản,anh em có thể hiểu là tìm ra những nhóm User tương tự nhau từ đó sẽ đưa ra dự đoán mực độ quan tâm của User trên các User khác cũng nhóm . Về chi tiết mình sẽ nói ỏ phần 2

    iiCF : Tương tự như User-User, phương pháp này sẽ tìm ra những nhóm item tương tự nhau. Sau đó, dự đoán mức độ yêu thích của user với item dựa trên độ yêu thích của user đó với các item khác cùng loại. Về chi tiết mình sẽ nói ở phần 3

    User-user Collaborative Filtering

    Đầu vào của bài toán là Utility matrix và công việc quan trọng nhất trong uuCF là phải xác định được sự giống nhau giữa hai User và cách xác định sự giống nhau này dựa trên độ quan tâm với các item giữa các User. Ví dụ nhé:

    Hình trên là 1 ví dụ về đầu vào là utility matrix dựa trên số sao rating của các user với item. Nhìn phát thấy luôn là User 1 và 0 cho rating về các item khá giống nhau ít ra còn giống hơn mấy các User còn lại vậy nên ta có thể đoàn rằng user 0 cũng quan tâm tới item 2 như user 1

    Vậy để thuận tiện tính toán similarity giữa các User ta phải điền giá trị vào các ô ‘?’. Vậy mỗi ô ‘?’ cần được điền giá trị như thế nào để thích hợp, có thể nhiều người sẽ nghĩ đến là 0 nhưng điều này mình đánh giá sẽ ảnh hưởng khá lớn trong việc đưa ra gợi ý vì mức 0 có nghĩa đây là 1 mức khá tiêu cực đối với item. Một giá trị mình thấy rất khả quan hơn trong trường hợp này chính là giá trị trung bình cộng của các ratings mà User đã đánh giá cho các item còn lại. Ví dụ như ở user đầu ta có thể tính được giá trị trung bình này là 3.25 được tính từ trung bình cộng của 5-3-2-2. Ta sẽ tính được utility matrix

    Tiếp theo chúng ta sẽ xây dựng normalized utility matrix bằng cách trừ mỗi rating đi với giá trị trung bình. Vậy tại sao lại cần bước chuẩn hóa này lại cần thiết và quan trọng như vâỵ thì rất dễ hiểu thôi:

    • Việc trừ đi trung bình cộng của mỗi cột khiến trong trong mỗi cột có những giá trị dương và âm và 0 ( là giá trị chưa xác định ) . Những giá trị âm và dương này đại diện cho sự quan tâm của User đến Item là thích hoặc không thích còn 0 là đại diện cho những User không có chứng kiến =)) hiểu nôm na là chưa xác định được có thích hay không.
    • Về mặt kỹ thuật, số chiều của utility matrix là rất lớn với hàng triệu users và items, nếu lưu toàn bộ các giá trị này trong một ma trận thì khả năng cao là sẽ không đủ bộ nhớ. Quan sát thấy rằng vì số lượng ratings biết trước thường là một số rất nhỏ so với kích thước của utility matrix, sẽ tốt hơn nếu chúng ta lưu ma trận này dưới dạng sparse matrix, tức chỉ lưu các giá trị khác không và vị trí của chúng. Vì vậy, tốt hơn hết, các dấu ‘?’ nên được thay bằng giá trị ‘0’, tức chưa xác định liệu user có thích item hay không. Việc này không những tối ưu bộ nhớ mà việc tính toán similarity matrix sau này cũng hiệu quả hơn.

    Ma trận sau khi được chuẩn hóa còn được gọi là normalized utility matrix như hình dưới:

    Tính toán Similarity

    vậy sau khi xây dựng xong normalized utility matrix , bước quan trọng tiếp theo chúng cần cần làm là tính toán độ tương đồng giữa các User.

    Ta gọi mực độ tương đồng của 2 User là Sim(Ui,Uj). Để xây dựng 1 hàm Similarity thì chúng ta cần đảm bảo yếu tố sau :

    Ở đây mình sẽ đề cập đến 2 similarity function đó là

    • Cosine Similarity : Đây là hàm được sử dụng nhiều nhất, và cũng quen thuộc với các bạn nhất. Nếu các bạn không nhớ công thức tính cos của góc giữa hai vector u1 , u2 trong chương trình phổ thông, thì dưới đây là công thức:

    Trong bài này mình sẽ sử dụng công thức này nhé.

    • Pearson Corelation : Mình thường k hay sử dụng công thức này , anh em có thể tham khảo thêm ở đây

    Sau khi sử dụng Cosine Similarity thì chúng ta sẽ thu được ma trận Similarity như sau:

    Rating Prediction

    Sau khi xây dựng được ma trận Similarity thì chúng ta phải đưa ra dự đoán đúng không nào? Ở đây chúng ta sẽ dự đoán theo K- User gần nhất . K càng nhiều thì dự đoán sẽ càng chính xác nghe khá giống với K-NN nhỉ.

    Công thức được đưa ra ở đây là:

    Để mình lấy ví dụ minh họa dự đoán user 5 rating cho item 3 với K = 3 luôn cho anh em dễ hiểu nhé:

    • Xác định các User đã rated cho item 3 là User 0,1,2,3,4,6
    • Xác định similarities của User 5 với các User còn lại lần lượt là : 0.2 , -0.23 , 0.47 , -0.29 , 0 , 0.56 với K = 3 thì ta chọn 0,2,6
    • Xác định Normalized ratings của User 0,2,6 lần lượt là -1.25 , 0.5 , 0.67
    • Đưa ra dự đoán theo công thức :

    Thực hiện tương tự là ta có thể hoàn thiện normalized ratings matrix :

    Đến bước này là gần như đã xong việc cuối cùng của ae là cộng lại với gái trị trung bình ban đầu tính được là ta có thể đưa ra dự đoán của 1 User với 1 Item rồi

    Item-item Collaborative Filtering

    Một số hạn chês của User-user CF:

    • Trên thực tế, số lượng users luôn lớn hơn số lượng items rất nhiều. Kéo theo đó là Similarity matrix là rất lớn với số phần tử phải lưu giữ là hơn 1 nửa của bình phương số lượng users (chú ý rằng ma trận này là đối xứng). Việc này, như đã đề cập ở trên, khiến cho việc lưu trữ ma trận này trong nhiều trường hợp là không khả thi.
    • Ma trận Utility Y thường là rất sparse. Với số lượng users rất lớn so với số lượng items, rất nhiều cột của ma trận này sẽ rất sparse, tức chỉ có một vài phần tử khác 0. Lý do là users thường lười rating. Cũng chính vì việc này, một khi user đó thay đổi rating hoặc rate thêm items, trung bình cộng các ratings cũng như vector chuẩn hoá tương ứng với user này thay đổi nhiều. Kéo theo đó, việc tính toán ma trận Similarity, vốn tốn nhiều bộ nhớ và thời gian, cũng cần được thực hiện lại.

    Ngược lại, nếu chúng ta tính toán similarity giữa các items rồi recommend những items gần giống với item yêu thích của một user thì sẽ có những lợi ích sau:

    • Vì số lượng items thường nhỏ hơn số lượng users, Similarity matrix trong trường hợp này cũng nhỏ hơn nhiều, thuận lợi cho việc lưu trữ và tính toán ở các bước sau.
    • Vì số lượng phần tử đã biết trong Utility matrix là như nhau nhưng số hàng (items) ít hơn số cột (users), nên trung bình, mỗi hàng của ma trận này sẽ có nhiều phần tử đã biết hơn số phần tử đã biết trong mỗi cột. Việc này cũng dễ hiểu vì mỗi item có thể được rated bởi nhiều users. Kéo theo đó, giá trị trung bình của mỗi hàng ít bị thay đổi hơn khi có thêm một vài ratings. Như vậy, việc cập nhật ma trận Similarity Matrix có thể được thực hiện ít thường xuyên hơn.

    Cách tiếp cận thứ hai này được gọi là Item-item Collaborative Filtering. Mình thấy hướng tiếp cận này được sử dụng nhiều trong thực tế hơn.

    Quy trình dự đoán missing ratings cũng tương tự như trong User-user CF

    Đầu tiên tính giá trị trung bình của rating theo item:

    Xây dựng normalized utility matrix :

    Xây dựng Item similarity matrix :

    Đưa ra dự đoán còn thiếu:

    Trên đây là lý thuyết về NBCF. Mình xin kết thúc bài viết này ở đây , ở phần sau mình sẽ đi vào code Python và kiểm thử dữ liệu cho anh em nhé . Hẹn ae ở bài viết tới

    Tài liệu mình hay tham khảo

    1. Khá hay và nhiều kiến thức của các pháp sư US-UK AWS Machine Learning Blog

    2. Kho Dataset cho anh em GroupLens

    3. Mình cũng hay tham khảo ở đây TensorFlowBlog

  • Map, FlatMap,… trong Kotlin

    Map, FlatMap,… trong Kotlin

    Giới thiệu

    Kotlin sinh ra extension function làm cho việc tuân thủ nguyên tắc open/close trở nên dễ dàng hơn. Với extension function ta không cần phải kế thừa từ một class khi muốn mở rộng chức năng.

    Có thể thấy extension function là thứ rất mạnh trong kotlin, cũng nhờ nó mà collections trong kotlin trở lên mạnh mẽ và làm cho việc lập trình đơn giản hơn rất nhiều.

    Bài viết này mình sẽ giới thiệu một số chức năng trong collections kotlin:

    1. filter
    2. map
    3. flatMap
    4. groupBy
    5. partition

    1. filter

    Chức năng này trả về một list mới gồm các phần tử thỏa mãn predicate.

    inline fun <T> Iterable<T>.filter(
        predicate: (T) -> Boolean
    ): List<T>
    

    Ví dụ trả về danh sách các số chẵn:

    listOf(1,2,3,4,5).filter { number->
        number%2 == 0
    }
    

    2. map

    Chức năng này giúp chuyển đổi một collection thành một list sau phép biến đổi hàm ánh xạ transform T -> R mà ta định nghĩa.

    inline fun <T, R> Iterable<T>.map(
        transform: (T) -> R
    ): List<R>
    

    Kiểu trả về của danh sách sau phép map phụ thuộc vào kiểu trả về của lambda transform.

    Ví dụ: Cho một danh sách sinh viên, điểm gpa cuối khóa sẽ được sử dụng để xét làm giảng viên. Một sinh viên được làm giảng viên nếu GPA > 3.8. Trả về danh sách giảng viên.

    Ta sẽ kết hợp filter và map để làm ví dụ xàm này.

    data class Student(val name:String, val gpa: Float)
    
    data class Teacher(val name:String)
    
    val students = getStudents()
    val teachers = students.filter { it.gpa > 3.8 }
            .map { Teacher(it.name) }
    

    Có thể thấy dùng filter + map làm code ngắn gọn dễ hiểu hơn nhiều đúng không nào.

    3. flatMap

    Nhìn thằng này chả khác gì thằng map ngoài thêm prefix flat, với một thằng ngu english như mình sau khi dịch flat thì chị google cho mình kết quả là phẳng, phẳng như nào thì cùng xem tiếp nhé.

    Đây là hàm flatMap

    inline fun <T, R> Iterable<T>.flatMap(
        transform: (T) -> Iterable<R>
    ): List<R>
    

    flatMap khác map duy nhất chỗ kiểu trả về của lambda transform là Iterable<R> thay vì R.

    flatMap sẽ map mỗi phần tử kiểu T thành một Iterable<R> . Cùng xem cách mà flatMap hoạt động dưới đây ta sẽ hiểu sao lại phẳng.

    Các list trả về sau khi mỗi phần tử transform sẽ được addAll vào một list duy nhất là destination. Nếu dùng map thì sẽ trả về một list mà các phần tử trong đó là các list có độ dài khác nhau.

    public inline fun <T, R> Iterable<T>.flatMap(transform: (T) -> Iterable<R>): List<R> {
        //Trả về giá trị của hàm flatMapTo
        //transform là phép biến đổi T -> Iterable<R> mà ta truyền vào
        return flatMapTo(ArrayList<R>(), transform)
    }
    
    public inline fun <T, R, C : MutableCollection<in R>> Iterable<T>.flatMapTo(destination: C, transform: (T) -> Iterable<R>): C {
        //Duyệt tất cả phần tử trong danh sách ban đầu
        for (element in this) {
    	//Với mỗi phần tử biến đổi thành một list bởi hàm transform
            val list = transform(element)
    	//Thêm vào arrayList
            destination.addAll(list)
        }
        return destination
    }
    

    flatMap rất hữu ích khi muốn transform một list với quan hệ 1-N.

    Ví dụ: Một ứng dụng nghe nhạc có chức năng cho người dùng chọn nhiều thể loại và trả về tất cả các bài hát trong các thể loại đó. Người dùng lại tài khoản vip nên mỗi bài hát lấy ra sẽ được chuyển định dạng thành vip.

    Ta có thể thấy thể loại và bài hát có quan hệ 1-N ta nghĩ ngay đến flatMap.

    data class Song(val name: String, val singer: String)
    
    data class VipSong(val name: String, val singer: String)
    
    data class Category(val name: String, val songs: List<Song>)
    ...
    val categories = listOf<Category>()
    val vipSongs = categories.flatMap { category ->
        category.songs.map { VipSong(it.name, it.singer) }
    }
    

    4. groupBy

    Hàm này có chức năng nhóm các phần tử trong collection theo selector và trả về một map collection với các key theo selector. Ví dụ: Liệt kê các học sinh theo tên cuong -> {Student("cuong", id = 1)}

    data class Grade(val math: Float, val physics: Float)
    
    data class Student(val name: String, val grade: Grade)
    ...
    
    val students = listOf(
            Student("Cuong1", Grade(1f,2f)),
            Student("Cuong2", Grade(3f,3f)),
            Student("Cuong3", Grade(1f,2f)),
            Student("Cuong5", Grade(1.2f,2.5f))
        )
    print(students.groupBy {
        it.grade
    })
    

    Kết quả sẽ trả về một map collection:

    {
    	Grade(math=1.0, physics=2.0)=[Student(name=Cuong1, grade=Grade(math=1.0, physics=2.0)), Student(name=Cuong3, grade=Grade(math=1.0, physics=2.0))],
    	Grade(math=3.0, physics=3.0)=[Student(name=Cuong2, grade=Grade(math=3.0, physics=3.0))], 
    	Grade(math=1.2, physics=2.5)=[Student(name=Cuong5, grade=Grade(math=1.2, physics=2.5))]
    }
    

    5. Partition

    Hàm này có chức năng phân chia collection thành hai list theo điều kiện, một list là thỏa mãn điều kiện, một list là không thỏa mãn điều kiện.

    Ví dụ: Cần lấy danh sách sinh viên được tốt nghiệp và sinh viên chưa được tốt nghiệp

    data class Student(val name: String, val gpa: Float, val credits: Int)
    
    fun isGraduated(student: Student) = student.run { gpa>=2.5 && credits == 150}
    
    fun main() {
        val students = listOf(
            Student("Lan", 4.0f, 140),
            Student("Phuong", 2.45f, 150),
            Student("MA", 2.7f, 150)
        )
        val (graduated, undergraduate) = students.partition(::isGraduated)
        println("""
            graduated: $graduated
            undergraduate: $undergraduate
        """.trimIndent())
    }
    

    Kết quả:

    graduated: [Student(name=MA, gpa=2.7, credits=150)]
    undergraduate: [Student(name=Lan, gpa=4.0, credits=140), Student(name=Phuong, gpa=2.45, credits=150)]
    

    Kết luận

    Các chức năng này giúp chúng ta giảm thiếu số lượng mã cũng như code clear hơn, nó cũng quan trọng và gặp thường xuyên khi làm việc với các thư viện reactive như Rx, flow coroutine.

  • Tổng quan về Recommendation Systems – Phần 1

    Tổng quan về Recommendation Systems – Phần 1

    Tổng quan về Recommendation Systems – Phần 1

    Recommendation Systems

    Xin chào mọi người, đây là bài đầu tiên của mình về chủ đề Machine Learning và cũng là bài đầu tiên về Series Recommendation Systems này, mặc dù chủ đề này không có liên quan đến công việc của mình nhưng do sở thích hay đi đọc block dạo và cũng muốn thử học hỏi thêm tý kiến thức khác nên mình quyết định viết lên series này vì vậy sẽ có nhiều thiếu sót nên mong các anh em có thể góp ý cho mình , gạch đá như nào mình gom hết về xây nhà, nhà em cũng đang thiếu ít gạch

    Nội dung trong phần này

    Trong phần này mình sẽ giới thiệu chung về hệ thống Recommendation và hai nhóm chính của RS, ở bài viết sau mình sẽ đi chi tiết và những nhóm chính để mọi người có thể có cái nhìn chi tiết nhất, bài đầu này như kiểu món tráng miệng cho anh em thôi.

    Giới thiệu về hệ thống

    Mình tin chắc rằng những anh(chị) em ở đây đã gặp phải 1 trong những trường hợp này thường xuyên trong cuộc sống:

    • Khi xem hết 1 video trên youtube hoặc sắp hết sẽ có 1 loạt các gợi ý các video tiếp theo cho bạn xem kể bạn có là chiếu mới khi xem youtube thì họ vẫn có thể đưa cho bạn 1 list video và tất nhiên sẽ có cái mà bạn thích
    • Đắng lòng hơn là khi bạn lỡ nói hoặc tìm kiếm cái gì đó trên google thì khi bạn sử dụng dịch vụ của Google hay lướt news trên Facebook thì sẽ có hàng loạt các gợi ý về sản phẩm tương tự cho bạn , hoặc lỡ bạn có like 1 vài item nào đó trên nên tảng của họ thì bạn cũng sẽ nhận được 1 rổ gợi ý về các loại item đấy cho bạn
    • Trên các sàn thương mại điện tử thì càng ác liệt hơn khi đây chính là cách mà họ moi tiền trong thẻ tín dụng của bạn, nhất là các ông lớn như Amazon , Shopee , Lazada. Mỗi khi bạn mua 1 sản phẩm nào đó thì họ sẽ yêu cầu bạn đánh giá sản phẩm ý để lấy rating ( cái để phục vụ cho họ để đưa ra gợi ý chính xác nhất ) nếu bạn không Rating thì họ sẽ gửi mail , bật thông báo để đòi bạn bao giờ rating mới thôi thế nên mình toàn rating cho có .

    Còn rất nhiều các ví dụ khác mà hệ thống có khả năng tự gợi ý cho người dùng những sản phẩm họ có thể thích đây chính là lý do vì sao mà anh em ta đi mua đồ trên các trang web hay thương mại điện tử thường vượt quá budget. Bằng cách quảng cáo đúng tim đen của người dùng thì doanh thu cũng tăng lên và những thuật toán đằng sau những ứng dụng này là những thuật toán Machine Learning có cách gọi chung là Recommendation Systems – Hệ thống gợi ý

    Recommemdation Systems là 1 trong những mảng tương đối lớn của Machine Learning và có tuổi đời đã khá lớn khi lần đầu tiên được đề cập trong 1 báo cáo kĩ thuật năm 1990 bởi Jussi Karlgren tại Đại Học Columbia và được triển khai quy mô lớn từ năm 1994 trở đi bởi Jussi Karlgren . RS là 1 giải pháp thay thế cho các thuật toán tìm kiếm ví chúng giúp người dùng có thế thấy được các item mà họ có thể thích kể cả họ có tìm tiếm hay không.

    Các thực thể chính trong hệ thống

    Như anh em đã biết thì để làm việc hay xây dựng lên 1 hệ thống thì điều đầu tiên chúng ta cần xác minh là cần những thành phần nào để tạo ra hệ thống. Nói đến hệ thống gợi ý thì chúng ta cần phải có tối thiểu 2 yếu tố sau:

    • User : Rõ ràng luôn, không có người dùng thì gợi ý cho vong ỏ? các đặc điểm của User thường được sử dụng trong gợi ý kết bạn điển hình là Facebook.
    • Item : Nó lại là 1 điều hiển nhiên luôn vì có người dùng mà k có sản phẩm thì gợi ý cho nhau à? Đúng , nếu không có 1 item cụ thể nào đó mà chỉ có người dùng thì chỉ có thể gợi ý người dùng khác cho nhau và các anh em biết cái ứng dụng nào đang sử dụng rồi đó , chính là Tinder nhưng trong trường hợp này User lại tính là 1 item trong bài toán gợi ý kết bạn hay kết nối với nhau.
    • Rating : Thực ra đây là 1 yếu tố mình nghĩ trong 1 vài hệ thống gợi ý sẽ không cần đến nhưng đa số thì đây là 1 yếu tố rất quan trọng để đưa ra gợi ý chính xác nhất cho người dùng. Vì rating hay feedback rất quan trọng , nó mô tả sự quan tâm của 1 người dùng nào đó đến với 1 item nó đó qua đó có thể đưa ra những gợi ý chính xác nhất cho khách hàng.

    Và sau đây mình sẽ đề cập đến 2 nhóm chính trong RS, tất nhiên trong Recommendation Systems có rất nhiều nhóm khác nữa nhưng những nhóm ý chúng ta sẽ đi ở các bài viết khác nhé vì chúng khác là trừu tượng và dài.

    Hai nhóm chính của Recommendation Systems

    Các hệ thống gợi ý (RS) thường được chia làm 2 nhóm chính lớn:

    • Content-based systems: Hệ thống sẽ quan tâm đến đặc điểm của mục tiêu ví dụ như khi bạn nghe Lạc Trôi , Em của ngày hôm qua , Nắng ấm xa dần thì hệ thống sẽ phân tích ra các bài hát bạn vừa nghe là của Sơn Tùng thì hệ thống sẽ chuẩn đoán bạn đích thực là 1 SKY rồi thế là nhồi cho bạn 1 list nhạc của MTP luôn , User cũng tương tự trong bài toán gợi ý kết bạn hay lướt tinder ví dụ bạn hay thả tym cho các cô gái 1m5-1m6 tuổi 18-20 , nhà Tây Hồ đi Mer thì Hệ thống sẽ đề xuất cho bạn làm trạn vương
    • Collaborative filtering: Nhóm này thì đẳng cấp hơn khi gợi ý các item dựa trên sự tương quan (similarity) giữa các User và(hoặc) Item, hơi khó hiểu nhỉ để dễ hình dùng hơn là nhóm này gợi ý dựa trên rating của User với Item hay được recommended tới User dự trên những User có hành vi tương tự. Ví dụ: Có 4 cô A,B,C,D đều thích nhạc của Sơn Tùng và là SKY chân chính luôn. Ngoài ra hệ thống còn có thông tin 2 cô A,B đều ghét nhạc của JACK mà k biết 2 cô kia thế nào? Dựa trên phán đoán của hệ thống có thể đề xuất cả 2 cô còn lại đều ghét nhạc của JACK bằng cách rating 1 sao hoặc dislike nhạc và không bao giờ gợi ý nhạc JACK cho 2 cô còn lại . Trong CF này còn được chia ra làm 3 cách khách nhau như NCF (Neural Collaborative Filtering) , NBCF (Neighborhood-Based Collaborative Filtering) , MF(Matrix Factorization Collaborative Filtering) về chi tiết 3 cách này mình sẽ đi vào chi tiết ở các bài viết tới.

    Vậy chúng ta nên sử dụng phương pháp nào cho ứng dụng của mình?

    Có một điều dễ nhận thấy là nếu chúng ta sử dụng Collaborative filtering thì rõ ràng là chúng ta đã có 1 lượng data khá ổn định về rating , feedback của khách hàng để đưa ra đề xuất hợp lí và chính xác nhất chính vì vậy cách này được sử dụng khi bạn đã có 1 lượng thông tin đủ dày rồi nhưng cách này lại đưa ra đề xuất 1 cách chính xác hơn nhưng nếu bạn chưa có đủ lượng data cần thiết thì cách Content-based lại khá hữu ích khi bạn chưa có được lượng data về rating hay feedback mà chỉ có thông tin item mà User quan tâm. Chính vì vậy tùy vào tình huống , trường hợp của mỗi ứng dụng mà chúng ta sẽ sử dụng cách nào.

    Utility matrix

    Như đã đề cập, có hai thực thể chính trong các Recommendation Systems là users và items. Mỗi user sẽ có mức độ quan tâm (degree of preference) tới từng item khác nhau. Mức độ quan tâm này, nếu đã biết trước, được gán cho một giá trị ứng với mỗi cặp user-item. Giả sử rằng mức độ quan tâm được đo bằng giá trị user rate cho item, ta tạm gọi giá trị này là rating. Tập hợp tất cả các ratings, bao gồm cả những giá trị chưa biết cần được dự đoán, tạo nên một ma trận gọi là utility matrix. Xét vị dụ:

    Ví dụ về utility matrix

    Hình 1: Ví dụ về utility matrix với hệ thống Gợi ý.

    Các item được người dùng đánh giá từ 1 đến 5. Các dấu ‘?’ ứng với việc dữ liệu chưa tồn tại trong cơ sở dữ liệu. Nhiệm vụ của RS là phải tự điền các giá trị và các ô còn thiếu này và từ đó đưa ra gợi ý cho người dùng.

    Thông thường, có rất nhiều users và items trong hệ thống, và mỗi user thường chỉ rate một số lượng rất nhỏ các item, thậm chí có những user không rate item nào (với những users này thì cách tốt nhất là gợi ý các items phổ biến nhất). Vì vậy, lượng ô ‘?’ của utility matrix trong các bài toán đó thường là rất lớn, và lượng các ô đã được điền là một số rất nhỏ.

    Rõ ràng rằng càng nhiều ô được điền thì độ chính xác của hệ thống sẽ càng được cải thiện. Vì vậy, các hệ thống luôn luôn hỏi người dùng về sự quan tâm của họ tới sản phẩm, và muốn người dùng đánh giá càng nhiều sản phẩm càng tốt. Việc đánh giá các sản phẩm, vì thế, không những giúp các người dùng khác biết được chất lượng sản phẩm mà còn giúp hệ thống biết được sở thích của người dùng, qua đó có chính sách quảng cáo hợp lý.

    Không có utility matrix gần như là không thể đưa ra gợi ý chính xác tới người dùng cũng có thể đưa ra các sản phẩm phổ biến nhất. Vì vậy trong các Recommendation Systems, việc hoàn thiện hay xây dựng utility matrix là điều rất cần thiết nhưng việc xây dựng nó lại rất khó khăn vì khách hàng thường mua hàng xong là mất hút luôn mà k để lại bất kì dạng feedback gì cả chính vì vậy mà các ông lớn đã tìm ra rất nhiều cách để lấy cái feedback này của khách hàng và mình đúc kết lại có 3 cách chính sau để lấy rating của khách hàng:

    • Yêu cầu người dùng Rating sản phẩm, các ông lớn như Amazon, Alibaba , Shopee thường sẽ gửi mail liên tục nếu bạn không rating sẩn phẩm của họ hoặc thông báo đến bạn và rất nhiều trang thương mại điện tử cũng làm theo các cách này để lấy được rating của khách hàng nhưng nó lại khá là gây ức chế cho người dùng và dễ gây ra rating chống đối, không đúng mong muốn
    • Cách thứ hai đó là dựa theo hành vi người dùng , cách này khá là có triển vọng vì dựa vào hành vì chúng ta có thể kết luận được mức độ quan tâm của 1 user đến 1 item nào đó. Ví dụ bạn xem 1 video trên youtube rất nhiều lần thì có thể kết luận rằng bạn thích xem video đó hay là dựa vào các hành vi khách như Like , thả Tym trên facebook , mua 1 món đồ nào đó nhiều lần … Tất cả các hành vi của bạn đều phản ánh sự quan tâm của bạn đến 1 item nào đó vì trả ai ngáo đến nỗi xem đi xem lại 1 thứ nhiều lần trong khi rất ghét nó
    • Lấy rating từ 1 nguồn khác , điển hình là Facebook và Google , chắc chắn bạn đã thấy khi search google 1 cái gì đó hoặc tìm mua 1 món đồ nào đó trên các trang thương mại điện tử khác thì chỉ 1 lúc sau trên facebook bạn sẽ tràn ngập quảng cáo món đồ đó vì Facebook họ dùng 1 cái là Pixel. Anh em có thể hiểu nôm na là 1 đoạn mã nhỏ gắn vào cách website. Đoạn mã này hiểu nôm na nó cho Facebook biết ai là người đang sử dụng ứng dụng nào và cho Facebook biết các trạng thái của bạn như xem , tìm kiếm , thêm vào giỏ hàng , thanh toán … để đưa ra chính sách quảng cáo phù hợp . Kĩ thuật này còn gọi là Retargeting

    Có nhiều người thường cho rằng mấy ông lớn đang nghe lén bạn, nếu có thế thật thì chắc mấy ông lớn phải tìm hành tinh khác để lưu trữ dữ liệu và 1 thuật toán thần thánh nào đó để phân tích đống dữ liệu kia đủ nhanh

    Tản mạn đến đây thôi, ở bài viết sau mình sẽ đề cập chi tiết đến CBF, 1 trong cách nhánh chính của RS.Tấm chiếu mới trong viết bài về công nghệ như mình sẽ không tránh khỏi sai sót trong kiến thức, mong các huynh đệ có thể góp ý để có gạch xây nhà

    Tài liệu mình hay tham khảo

    1. Khá hay và nhiều kiến thức của các pháp sư US-UK AWS Machine Learning Blog

    2. Kho Dataset cho anh em GroupLens

    3. Mình cũng hay tham khảo ở đây TensorFlowBlog

    Còn rất nhiều Blog hay về AI , Machine Learning , Data Science nhưng khi nói về phần nào mình sẽ share về phần ý cho anh đỡ phân tâm nhé. Hẹn anh em ở bài viết lần sau nhé , mọi người có thể gọi mình là Yonko

  • Android Architecture – Tại sao chọn MVVM hơn là MVP

    Android Architecture – Tại sao chọn MVVM hơn là MVP

    Bài viết này, mình sẽ trình bày tại sao chọn MVVM hơn là MVP.

    I. Vấn đề

    Một số vấn đề để một lập trình viên quyết định chọn mô hình xây dựng ứng dụng như là làm sao để tái sử dụng code, dễ maintenance, dễ viết unit test hay dễ đọc hiểu với người mới vào trong dự án. Một số vấn đề trên dẫn đến việc chọn lựa mô hình khi bắt đầu một dự án mới là một điều hết sức quan trọng đối với mỗi lập trình viên. Hiện nay, có thể thấy 2 mô hình phổ biến nhất là MVVM và MVP. Trong bài viết này, chúng ta sẽ cùng tìm hiểu về chúng và xem cái nào ưu việt hơn.

    II. Giải pháp

    Bản thân Android được viết dưới dạng MVC trong đó Activity chịu trách nhiệm cho rất nhiều thứ trong đó bao gồm tất cả các logic. Với những ứng dụng đơn giản thì có thể mọi thứ vẫn còn dễ dàng, nhưng khi ứng dụng đủ lớn, số lượng logic tăng lên và mức độ vấn đề cũng tăng theo. Có nhiều mô hình tiếp cận khác nhau như MVP, MVVM,… được chứng minh là có thể giải quyết các vấn đề trên. Người ta có thể sử dụng bất kỳ cách tiếp cận nào, chúng thích ứng với các cách thay đổi một cách nhanh chóng,…

    III. Mục tiêu

    Xây dựng mọi thứ một cách phân tán như vậy để tách biệt dữ liệu – logic – view ra để đối với những project lớn khi số lượng logic và dữ liệu đủ lớn sẽ hữu ích trong việc mở rộng, bảo trì, test,…

    IV. Tại sao là MVVM?

    Có khá nhiều bài viết về MVP về sự sử dụng rộng rãi của mô hình này: Model — View — Presenter. Đó là một mô hình trưởng thành và ở mức độ nhất định, có thể giải quyết vấn đề nhưng vẫn có khá nhiều hạn chế và nó cần phải cải thiện một số thứ.

    Một mô hình MVP đơn giản như sau:

    Mô hình MVP

    Và một mô hình MVVM đơn giản như sau:

    Mô hình MVVM

    Hãy bắt đầu vào những hạn chế của MVP và cách chúng ta có thể khắc phục chúng bằng cách sử dụng MVVM.

    Đối với mỗi View thì đều yêu cầu 1 Presenter, đây là quy tắc ràng buộc cứng nhắc. Presenter giữ tham chiếu đến View và View cũng giữ tham chiếu đến Presenter. Mối quan hệ 1:1 và đó là vấn đề lớn nhất.

    Khi sự phức tạp hay độ lớn của ứng dụng tăng lên dẫn đến việc duy trì và xử lý mối quan hệ này cũng vậy.

    Chính vì những hạn chế trên của Presenter, MVVM được giới thiệ

    ViewModel là các class mô phỏng tương tác với logic/model layer và chỉ hiện trạng thái/ dữ liệu mà không quan tâm ai hoặc dữ liệu sẽ được tiêu thụ thế nào. Chỉ View giữ tham chiếu đến ViewModel và không có trường hợp ngược lại, điều này giải quyết vấn đề của Presenter và View. Một View có thể giữ tham chiếu nhiều ViewModel. Ngay cả một View cũng có thể giữ tham chiếu đến nhiều ViewModel.

    V. Khả năng test

    Bởi vì Presenter bị ràng buộc chặt chẽ với View, dẫn đến việc unit test trở nên hơi khó khăn. ViewModel thâm chí còn thân thiện hơn với Unit test dù chúng chỉ hiển thị trạng thái và do đó có thể được kiểm tra độc lập mà không yêu cầu kiểm tra dữ liệu được tiêu thụ như thế nào. Đây là 2 lý do chính làm cho sự phân biệt, lựa chọn rõ ràng ảnh hưởng đến khả năng unit test của 2 mô hình.

    VI. Tổng kết

    Các mô hình này đang tiếp tục phát triển và MVVM có thể nói tiềm năng để trở nên mạnh mẽ, hữu ích nhưng tuyệt vời để thực hiện. MVP cũng rất hữu dụng và phổ biến nhưng chưa có thể hoàn hảo. Không có thể chắc chắn về tương lai, phù hợp tốt cho tất cả các giải pháp. Người ta có thể thích hoặc không thích MVVM nhưng đó cũng không quá quan trọng, miễn là chúng ta đạt được mục tiêu đang đáp ứng tốt cho project phát triển. Đây cũng là một số cảm nhận khi mình sử dụng qua 2 mô hình này. Do chưa có kinh nghiệm nên bài viết này không thể tránh khỏi sai sót, rất mong nhận được góp ý từ mọi người.

    Trên đây là 1 số chia sẻ về hạn chế của MVP và nó có thể khắc phục bằng MVVM. Cảm ơn các bạn đã theo dõi bài viết!

    Tham khảo: https://android.jlelse.eu/why-to-choose-mvvm-over-mvp-android-architecture-33c0f2de5516

  • Tổng quan thư viện Underthesea – bộ công cụ mã nguồn mở xử lý ngôn ngữ tự nhiên tiếng Việt

    Tổng quan thư viện Underthesea – bộ công cụ mã nguồn mở xử lý ngôn ngữ tự nhiên tiếng Việt

    Giới thiệu thư viện Underthesea – bộ công cụ mã nguồn mở xử lý ngôn ngữ tự nhiên tiếng Việt

    Mở đầu

    Underthesea là một toolkit hỗ trợ cho việc nghiên cứu và phát triển xử lý ngôn ngữ tự nhiên tiếng Việt. Underthesea ra đời vào tháng 3 năm 2017, trong bối cảnh ở Việt Nam đã có một số toolkit khá tốt như vn.vitk, pyvi, nhưng vẫn thiếu một toolkit hoàn chỉnh, mã nguồn mở, dễ dàng cài đặt và sử dụng như các sản phẩm tương đương đối với tiếng Anh như nltk, polyglot, spacy.

    Trong bài viết này chúng ta sẽ tìm hiểu sơ qua về Underthesea và một số cách sử dụng của nó.

    Underthesea là :

    1. Một bộ công cụ NLP tiếng Việt <br> Underthesea là một mã nguồn mở bằng Python bao gồm các bộ dữ liệu (data sets) và các hướng dẫn hỗ trợ nghiên cứu và phát triển trong xử lý ngôn ngữ tự nhiên tiếng Việt (Vietnamese Natural Language Processing). Nó cung cấp các API cực kỳ dễ dàng để áp dụng các mô hình pretrained NLP cho văn bản tiếng Việt, chẳng hạn như phân đoạn từ, gắn thẻ một phần giọng nói(PoS), nhận dạng thực thể có tên (NER), phân loại văn bản và phân tích cú pháp phụ thuộc.

    2. Một thư viện Pytorch <br> Underthesea được hỗ trợ bởi một trong những thư viên học sâu phổ biến nhất, Pytorch, giúp nó dễ dàng train các mô hình học sâu và thử nghiệp các phương pháp tiếp cận mới bằng cách sử dụng các Module và Class của Underthesea

    3. Một phần mềm mã nguồn mở <br> Underthesea được công bố theo giấy phép GNU General Public License v3.0. Các quyền của giấy phép này có điều kiện là cung cấp mã nguồn hoàn chỉnh của các tác phẩm được cấp phép và sửa đổi, bao gồm các tác phẩm lớn hơn sử dụng tác phẩm được cấp phép, theo cùng một giấy phép.

    Cài đặt

    Để cài đặt underthesea :

    $ pip install underthesea
    

    Hướng dẫn

    1. Phân đoạn câu (Sentence Segmentation)
    >>> from underthesea import sent_tokenize
    >>> text = 'Taylor cho biết lúc đầu cô cảm thấy ngại với cô bạn thân Amanda nhưng rồi mọi thứ trôi qua nhanh chóng. Amanda cũng thoải mái với mối quan hệ này.'
    
    >>> sent_tokenize(text)
    [
      "Taylor cho biết lúc đầu cô cảm thấy ngại với cô bạn thân Amanda nhưng rồi mọi thứ trôi qua nhanh chóng.",
      "Amanda cũng thoải mái với mối quan hệ này."
    ]
    
    1. Phân đoạn từ (Word Segmentation)
    >>> from underthesea import word_tokenize
    >>> sentence = 'Chàng trai 9X Quảng Trị khởi nghiệp từ nấm sò'
    
    >>> word_tokenize(sentence)
    ['Chàng trai', '9X', 'Quảng Trị', 'khởi nghiệp', 'từ', 'nấm', 'sò']
    
    >>> word_tokenize(sentence, format="text")
    'Chàng_trai 9X Quảng_Trị khởi_nghiệp từ nấm sò'
    
    1. Gán nhãn POS
    >>> from underthesea import pos_tag
    >>> pos_tag('Chợ thịt chó nổi tiếng ở Sài Gòn bị truy quét')
    [('Chợ', 'N'),
     ('thịt', 'N'),
     ('chó', 'N'),
     ('nổi tiếng', 'A'),
     ('ở', 'E'),
     ('Sài Gòn', 'Np'),
     ('bị', 'V'),
     ('truy quét', 'V')]
    
    1. Chunking
    >>> text = 'Bác sĩ bây giờ có thể thản nhiên báo tin bệnh nhân bị ung thư?'
    >>> chunk(text)
    [('Bác sĩ', 'N', 'B-NP'),
     ('bây giờ', 'P', 'I-NP'),
     ('có thể', 'R', 'B-VP'),
     ('thản nhiên', 'V', 'I-VP'),
     ('báo tin', 'N', 'B-NP'),
     ('bệnh nhân', 'N', 'I-NP'),
     ('bị', 'V', 'B-VP'),
     ('ung thư', 'N', 'I-VP'),
     ('?', 'CH', 'O')]
    
    1. Phân tích cú pháp phụ thuộc
    >>> from underthesea import dependency_parse
    >>> text = 'Tối 29/11, Việt Nam thêm 2 ca mắc Covid-19'
    >>> dependency_parse(text)
    [('Tối', 5, 'obl:tmod'),
     ('29/11', 1, 'flat:date'),
     (',', 1, 'punct'),
     ('Việt Nam', 5, 'nsubj'),
     ('thêm', 0, 'root'),
     ('2', 7, 'nummod'),
     ('ca', 5, 'obj'),
     ('mắc', 7, 'nmod'),
     ('Covid-19', 8, 'nummod')]
    
    1. Gán nhãn thực thể có tên (Named Entity Recognition)
    >>> from underthesea import ner
    >>> text = 'Chưa tiết lộ lịch trình tới Việt Nam của Tổng thống Mỹ Donald Trump'
    >>> ner(text)
    [('Chưa', 'R', 'O', 'O'),
     ('tiết lộ', 'V', 'B-VP', 'O'),
     ('lịch trình', 'V', 'B-VP', 'O'),
     ('tới', 'E', 'B-PP', 'O'),
     ('Việt Nam', 'Np', 'B-NP', 'B-LOC'),
     ('của', 'E', 'B-PP', 'O'),
     ('Tổng thống', 'N', 'B-NP', 'O'),
     ('Mỹ', 'Np', 'B-NP', 'B-LOC'),
     ('Donald', 'Np', 'B-NP', 'B-PER'),
     ('Trump', 'Np', 'B-NP', 'I-PER')]
    
    1. Phân loại văn bản
    >>> from underthesea import classify
    
    >>> classify('HLV đầu tiên ở Premier League bị sa thải sau 4 vòng đấu')
    ['The thao']
    
    >>> classify('Hội đồng tư vấn kinh doanh Asean vinh danh giải thưởng quốc tế')
    ['Kinh doanh']
    
    >> classify('Lãi suất từ BIDV rất ưu đãi', domain='bank')
    ['INTEREST_RATE']
    
    1. Phân tích cảm xúc
    >>> from underthesea import sentiment
    
    >>> sentiment('hàng kém chất lg,chăn đắp lên dính lông lá khắp người. thất vọng')
    negative
    >>> sentiment('Sản phẩm hơi nhỏ so với tưởng tượng nhưng chất lượng tốt, đóng gói cẩn thận.')
    positive
    
    >>> sentiment('Đky qua đường link ở bài viết này từ thứ 6 mà giờ chưa thấy ai lhe hết', domain='bank')
    ['CUSTOMER_SUPPORT#negative']
    >>> sentiment('Xem lại vẫn thấy xúc động và tự hào về BIDV của mình', domain='bank')
    ['TRADEMARK#positive']
    
    1. Tài nguyên NLP tiếng Việt

    Danh sách tài nguyên

    $ underthesea list-data
    | Name                | Type        | License | Year | Directory                    |
    |---------------------+-------------+---------+------+------------------------------|
    | UIT_ABSA_RESTAURANT | Sentiment   | Open    | 2021 | datasets/UIT_ABSA_RESTAURANT |
    | UIT_ABSA_HOTEL      | Sentiment   | Open    | 2021 | datasets/UIT_ABSA_HOTEL      |
    | SE_Vietnamese-UBS   | Sentiment   | Open    | 2020 | datasets/SE_Vietnamese-UBS   |
    | CP_Vietnamese-UNC   | Plaintext   | Open    | 2020 | datasets/CP_Vietnamese-UNC   |
    | DI_Vietnamese-UVD   | Dictionary  | Open    | 2020 | datasets/DI_Vietnamese-UVD   |
    | UTS2017-BANK        | Categorized | Open    | 2017 | datasets/UTS2017-BANK        |
    | VNTQ_SMALL          | Plaintext   | Open    | 2012 | datasets/LTA                 |
    | VNTQ_BIG            | Plaintext   | Open    | 2012 | datasets/LTA                 |
    | VNESES              | Plaintext   | Open    | 2012 | datasets/LTA                 |
    | VNTC                | Categorized | Open    | 2007 | datasets/VNTC                |
    
    $ underthesea list-data --all
    

    Download tài nguyên

    $ underthesea download-data VNTC
    100%|██████████| 74846806/74846806 [00:09<00:00, 8243779.16B/s]
    Resource VNTC is downloaded in ~/.underthesea/datasets/VNTC folder
    

    Các tính năng sắp ra mắt

    • Dịch máy
    • Chuyển văn bản thành giọng nói
    • Nhận dạng giọng nói tự động

    Kết bài

    Với Underthesea, chúng ta có thể dễ dàng cài đặt, sử dụng và tiết kiệm được lượng lớn thời gian thay vì phải gán nhãn bằng tay. Underthesea cũng là thư viện đắc lực hỗ trợ xử lý dữ liệu đầu vào cho rất nhiều bài toán khác.

    Cảm ơn các bạn đã giành thời gian đọc.

    Tham khảo: https://pypi.org/project/underthesea/

  • Tổng quan về Underthesea

    # **Giới thiệu thư viện Underthesea – bộ công cụ mã nguồn mở xử lý ngôn ngữ tự nhiên tiếng Việt**
    ## **Mở đầu**
    Underthesea là một toolkit hỗ trợ cho việc nghiên cứu và phát triển xử lý ngôn ngữ tự nhiên tiếng Việt. Underthesea ra đời vào tháng 3 năm 2017, trong bối cảnh ở Việt Nam đã có một số toolkit khá tốt như vn.vitk, pyvi, nhưng vẫn thiếu một toolkit hoàn chỉnh, mã nguồn mở, dễ dàng cài đặt và sử dụng như các sản phẩm tương đương đối với tiếng Anh như nltk, polyglot, spacy.
    Trong bài viết này chúng ta sẽ tìm hiểu sơ qua về Underthesea và một số cách sử dụng của nó.## **Underthesea** là : 1.  **Một bộ công cụ NLP tiếng Việt** <br>Underthesea là một mã nguồn mở bằng Python bao gồm các bộ dữ liệu (data sets) và các hướng dẫn hỗ trợ nghiên cứu và phát triển trong xử lý ngôn ngữ tự nhiên tiếng Việt ([Vietnamese Natural Language Processing](https://github.com/undertheseanlp/underthesea)). Nó cung cấp các API cực kỳ dễ dàng để áp dụng các mô hình pretrained NLP cho văn bản tiếng Việt, chẳng hạn như phân đoạn từ, gắn thẻ một phần giọng nói(PoS), nhận dạng thực thể có tên (NER), phân loại văn bản và phân tích cú pháp phụ thuộc.
    2. **Một thư viện Pytorch** <br>Underthesea được hỗ trợ bởi một trong những thư viên học sâu phổ biến nhất, [Pytorch](https://pytorch.org/), giúp nó dễ dàng train các mô hình học sâu và thử nghiệp các phương pháp tiếp cận mới bằng cách sử dụng các Module và Class của Underthesea
    3. **Một phần mềm mã nguồn mở** <br>Underthesea được công bố theo giấy phép GNU General Public License v3.0. Các quyền của giấy phép này có điều kiện là cung cấp mã nguồn hoàn chỉnh của các tác phẩm được cấp phép và sửa đổi, bao gồm các tác phẩm lớn hơn sử dụng tác phẩm được cấp phép, theo cùng một giấy phép.
    ### **Cài đặt**
    Để cài đặt underthesea :“`$ pip install underthesea“`
    ### **Hướng dẫn**
    1. **Phân đoạn câu** (Sentence Segmentation)“`>>> from underthesea import sent_tokenize>>> text = ‘Taylor cho biết lúc đầu cô cảm thấy ngại với cô bạn thân Amanda nhưng rồi mọi thứ trôi qua nhanh chóng. Amanda cũng thoải mái với mối quan hệ này.’
    >>> sent_tokenize(text)[  “Taylor cho biết lúc đầu cô cảm thấy ngại với cô bạn thân Amanda nhưng rồi mọi thứ trôi qua nhanh chóng.”,  “Amanda cũng thoải mái với mối quan hệ này.”]“`
    2. **Phân đoạn từ** (Word Segmentation)“`>>> from underthesea import word_tokenize>>> sentence = ‘Chàng trai 9X Quảng Trị khởi nghiệp từ nấm sò’
    >>> word_tokenize(sentence)[‘Chàng trai’, ‘9X’, ‘Quảng Trị’, ‘khởi nghiệp’, ‘từ’, ‘nấm’, ‘sò’]
    >>> word_tokenize(sentence, format=”text”)’Chàng_trai 9X Quảng_Trị khởi_nghiệp từ nấm sò’“`
    3. **Gán nhãn POS**“`>>> from underthesea import pos_tag>>> pos_tag(‘Chợ thịt chó nổi tiếng ở Sài Gòn bị truy quét’)[(‘Chợ’, ‘N’), (‘thịt’, ‘N’), (‘chó’, ‘N’), (‘nổi tiếng’, ‘A’), (‘ở’, ‘E’), (‘Sài Gòn’, ‘Np’), (‘bị’, ‘V’), (‘truy quét’, ‘V’)]“`
    4. **Chunking**“`>>> from underthesea import chunk>>> text = ‘Bác sĩ bây giờ có thể thản nhiên báo tin bệnh nhân bị ung thư?’>>> chunk(text)[(‘Bác sĩ’, ‘N’, ‘B-NP’), (‘bây giờ’, ‘P’, ‘I-NP’), (‘có thể’, ‘R’, ‘B-VP’), (‘thản nhiên’, ‘V’, ‘I-VP’), (‘báo tin’, ‘N’, ‘B-NP’), (‘bệnh nhân’, ‘N’, ‘I-NP’), (‘bị’, ‘V’, ‘B-VP’), (‘ung thư’, ‘N’, ‘I-VP’), (‘?’, ‘CH’, ‘O’)]“`
    5. **Phân tích cú pháp phụ thuộc**“`>>> from underthesea import dependency_parse>>> text = ‘Tối 29/11, Việt Nam thêm 2 ca mắc Covid-19’>>> dependency_parse(text)[(‘Tối’, 5, ‘obl:tmod’), (’29/11′, 1, ‘flat:date’), (‘,’, 1, ‘punct’), (‘Việt Nam’, 5, ‘nsubj’), (‘thêm’, 0, ‘root’), (‘2’, 7, ‘nummod’), (‘ca’, 5, ‘obj’), (‘mắc’, 7, ‘nmod’), (‘Covid-19’, 8, ‘nummod’)]“`
    6. **Gán nhãn thực thể có tên** (Named Entity Recognition)“`>>> from underthesea import ner>>> text = ‘Chưa tiết lộ lịch trình tới Việt Nam của Tổng thống Mỹ Donald Trump’>>> ner(text)[(‘Chưa’, ‘R’, ‘O’, ‘O’), (‘tiết lộ’, ‘V’, ‘B-VP’, ‘O’), (‘lịch trình’, ‘V’, ‘B-VP’, ‘O’), (‘tới’, ‘E’, ‘B-PP’, ‘O’), (‘Việt Nam’, ‘Np’, ‘B-NP’, ‘B-LOC’), (‘của’, ‘E’, ‘B-PP’, ‘O’), (‘Tổng thống’, ‘N’, ‘B-NP’, ‘O’), (‘Mỹ’, ‘Np’, ‘B-NP’, ‘B-LOC’), (‘Donald’, ‘Np’, ‘B-NP’, ‘B-PER’), (‘Trump’, ‘Np’, ‘B-NP’, ‘I-PER’)]“`
    7. **Phân loại văn bản**“`>>> from underthesea import classify
    >>> classify(‘HLV đầu tiên ở Premier League bị sa thải sau 4 vòng đấu’)[‘The thao’]
    >>> classify(‘Hội đồng tư vấn kinh doanh Asean vinh danh giải thưởng quốc tế’)[‘Kinh doanh’]
    >> classify(‘Lãi suất từ BIDV rất ưu đãi’, domain=’bank’)[‘INTEREST_RATE’]“`
    8. **Phân tích cảm xúc**“`>>> from underthesea import sentiment
    >>> sentiment(‘hàng kém chất lg,chăn đắp lên dính lông lá khắp người. thất vọng’)negative>>> sentiment(‘Sản phẩm hơi nhỏ so với tưởng tượng nhưng chất lượng tốt, đóng gói cẩn thận.’)positive
    >>> sentiment(‘Đky qua đường link ở bài viết này từ thứ 6 mà giờ chưa thấy ai lhe hết’, domain=’bank’)[‘CUSTOMER_SUPPORT#negative’]>>> sentiment(‘Xem lại vẫn thấy xúc động và tự hào về BIDV của mình’, domain=’bank’)[‘TRADEMARK#positive’]“`
    9. Tài nguyên NLP tiếng Việt
    Danh sách tài nguyên
    “`$ underthesea list-data| Name                | Type        | License | Year | Directory                    ||———————+————-+———+——+——————————|| UIT_ABSA_RESTAURANT | Sentiment   | Open    | 2021 | datasets/UIT_ABSA_RESTAURANT || UIT_ABSA_HOTEL      | Sentiment   | Open    | 2021 | datasets/UIT_ABSA_HOTEL      || SE_Vietnamese-UBS   | Sentiment   | Open    | 2020 | datasets/SE_Vietnamese-UBS   || CP_Vietnamese-UNC   | Plaintext   | Open    | 2020 | datasets/CP_Vietnamese-UNC   || DI_Vietnamese-UVD   | Dictionary  | Open    | 2020 | datasets/DI_Vietnamese-UVD   || UTS2017-BANK        | Categorized | Open    | 2017 | datasets/UTS2017-BANK        || VNTQ_SMALL          | Plaintext   | Open    | 2012 | datasets/LTA                 || VNTQ_BIG            | Plaintext   | Open    | 2012 | datasets/LTA                 || VNESES              | Plaintext   | Open    | 2012 | datasets/LTA                 || VNTC                | Categorized | Open    | 2007 | datasets/VNTC                |
    $ underthesea list-data –all“`
    Download tài nguyên
    “`$ underthesea download-data VNTC100%|██████████| 74846806/74846806 [00:09<00:00, 8243779.16B/s]Resource VNTC is downloaded in ~/.underthesea/datasets/VNTC folder“`
    ### Các tính năng sắp ra mắt– Dịch máy- Chuyển văn bản thành giọng nói- Nhận dạng giọng nói tự động
    ### **Kết bài**
    Với Underthesea, chúng ta có thể dễ dàng cài đặt, sử dụng và tiết kiệm được lượng lớn thời gian thay vì phải gán nhãn bằng tay. Underthesea cũng là thư viện đắc lực hỗ trợ xử lý dữ liệu đầu vào cho rất nhiều bài toán khác. <br>Cảm ơn các bạn đã giành thời gian đọc. <br>Tham khảo: [https://pypi.org/project/underthesea/](https://pypi.org/project/underthesea/)

  • Clean Architecture trong Android

    Clean Architecture trong Android

    Giới thiệu

    Clean Architecture là một kiến trúc lập trình được Robert C. Martin đề cập tại blog của ông vào năm 2012, đó là sự kiện quan trọng trong tư tưởng thiết kế phần mềm ảnh hưởng cho đến bây giờ.

    Clean Architecture có thể được sử dụng trong bất kỳ ứng dụng và nền tảng nào. Bài viết này mình xin được tập trung vào kiến trúc sạch trong phát triển ứng dụng android.

    Tổng quan kiến trúc sạch

    Có rất nhiều kiến trúc khác nhau trong lập trình nhưng chúng đều có một mục tiêu chung là tách biệt các mối quan tâm. Để đạt được sự tách biệt này cách chia phần mềm thành các layer đảm nhận các nghiệp vụ khác nhau.

    Một vài đặc điểm:

    • Dễ dàng test, các bussiness logic có thể test mà không có giao diện người dùng, cơ sở dữ liệu, bất kỳ yếu tố bên ngoài nào khác.
    • Giao diện người dùng có thể dễ dàng thay đổi mà không làm thay đổi phần còn lại của hệ thống.
    • Độc lập với các dữ liệu, ta có thể chuyển đổi các loại dữ liệu khác nhau mà không ảnh hưởng đến các layer khác.
    • Độc lập với các framework, điều này cho phép sử dụng các framework như các công cụ, thay vì phải nhồi nhét hệ thống của bạn phụ thuộc vào chúng.
    • Một layer chỉ biết layer phía dưới nó, layer trong cùng sẽ không biết gì về các layer khác(isolated) => tách biệt giữa các layer, layer business logic bên trong sẽ không phụ thuộc vào các layer khác.
      Mộ- Các vòng tròn đồng tâm càng ở trong càng cấp cao, module cấp cao không phụ thuộc vào module cấp thấp(Dependency Inversion principle). Ta sẽ rõ hơn trong chi tiết từng layer khi xây dựng ứng dụng android.
    • Áp dụng nguyên tắc SOLID.

    Clean Architecture trong ứng dụng Android

    Tùy thuộc vào đặc thù, quy mô dự án mà ta phân chia thành các layer khác nhau. Trong dự án android ta thường chia thành ba layer chính:

    • Domain
    • Data
    • Presenter

    Mỗi layer là một module trong Android Studio, giờ ta sẽ đi vào chi tiết từng layer.

    Domain layer

    • Domain layer là lớp chứa tất cả model và toàn bộ bussiness logic của ứng dụng, có thể coi đây là nơi chứa các policy còn các layer khác là nơi chứa các cơ chế.
    • Domain layer nằm trong cùng do đó sẽ không biết bất kỳ layer nào khác bên ngoài.
      Đây là module cấp cao, không phụ thuộc vào bất kỳ implementation của module cấp thấp nào mà chỉ phụ thuộc thông qua abstraction
    • Mỗi usecase đảm nhiệm một nhiệm vụ duy nhất (Single responsibility principle), ví dụ: GetData(), AddData(), …

    Tạo module domain với lib java or kotlin, do domain layer không phụ thuộc vào bất kỳ android framwork nào. Do domain layer chỉ chứa bussiness logic của app.


    Ta có thể thấy file gradle của module domain không chứa dependencies của android framework.

    Ở domain layer chỉ định nghĩa interface Repository, data layer chứa implementation mà domain đã định nghĩa.

    Presenter layer phụ thuộc usecase.

    Usecase tương tự như trong UML chứa một chức năng duy nhất, usecase chỉ phụ thuộc vào interface SchoolRepository (Nguyên tắc DI trong SOLID) mà không phụ thuộc trực tiếp repository tại data layer.

    class GetAllSchoolUseCase @Inject constructor(
        private val schoolRepository: SchoolRepository
    ) : IUseCase<Flow<List<School>>> {
    
        override fun invoke(): Flow<List<School>> = schoolRepository.getAllSchool()
    }

    Data layer

    Lớp này cung cấp cách thức để truy cập các nguồn dữ liệu trong room database hoặc internet. Các triển khai này sử dụng Repository pattern.

    Data layer được tạo là module library android.

    Tại data layer sẽ tạo class triển khai interface repository mà định nghĩa trong domain layer.

    class SchoolRepositoryImpl @Inject constructor(
        @DispatcherIO private val dispatcher: CoroutineDispatcher,
        private val schoolDao: SchoolDao,
        private val studentDao: StudentDao
    ) : SchoolRepository {
        ...
    }

    Để chuyển đổi qua lại giữa model và entity giữa domain layer và data layer ta dùng các function mapper.

    fun SchoolWithStudents.toSchool(): School {
        return this.run {
            School(
                schoolEntity.schoolID,
                schoolEntity.schoolName,
                schoolEntity.address,
                students.toStudents()
            )
        }
    }
    
    fun School.fromSchool(): SchoolEntity {
        return this.run {
            SchoolEntity(schoolID, schoolName, address)
        }
    }
    

    Presenter layer

    Tại đây chứa các code liên quan đến giao diện người dùng, layer này sẽ dependent các module khác.

    Do sử dụng một vài dependencies tại module data nên mình sử dụng api project(":data").

    Sử dụng MVVM

    • View: chịu trách nhiệm vẽ UI người dùng (Activity, Fragment, …). Lắng nghe hành động từ người dùng và gọi ViewModel sử lý, observe LiveData trong ViewModel.
    • Model: Chứa các bussiness login và data
    • ViewModel: Cầu nối giữa data và UI, ViewModel sẽ sử dụng các UseCase tại domain layer để thực hiện các nhiệm vụ.

    Mỗi màn hình(feature) sẽ là một subpackage trong package ui.

    ViewModel sử dụng các usecase để thực hiện các task khác nhau.

    @HiltViewModel
    class SchoolListViewModel @Inject constructor(
        private val getAllSchoolUseCase: GetAllSchoolUseCase,
        private val deleteSchoolUseCase: DeleteSchoolUseCase,
        private val deleteStudentUseCase: DeleteStudentUseCase,
        private val updateSchoolUseCase: UpdateSchoolUseCase,
        private val updateStudentUseCase: UpdateStudentUseCase
    ) : BaseViewModel<SchoolsViewState>() {
         ...
    }

    Kết luận

    Clean Architecture rất phù hợp với những dự án lớn phức tạp, có nhiều bussiness logic, giúp cho việc phát triển các tính năng và maintain dễ dàng hơn. Tuy nhiên với những dự án nhỏ và đơn giản hơn thì việc sử dụng clean architecture không mang lại hiệu quả và mất thời gian cho việc xây dựng ban đầu.

    Do chưa có kinh nghiệm nên bài viết này không thể tránh khỏi sai sót, rất mong nhận được góp ý từ các Anh.
    Author: CuongNV83