Author: tuanit2304

  • 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

  • Giới thiệu về Transfer learning và Fine-tuning (Phần 2)

    Giới thiệu về Transfer learning và Fine-tuning (Phần 2)

    Tiếp nối bài trước về Transfer Learning, hôm nay chúng ta cùng tìm hiểu về Fine Tuning.

    Mở đầu

    Fine tuning : Thuật ngữ này có thể được dịch là “Tinh chỉnh” – là một quá trình sử dụng một mô hình mạng đã được huấn luyện cho một nhiệm vụ nhất định để thực hiện một nhiệm vụ tương tự. Sở dĩ cách lý giải này có phần giống Transfer Learning – bởi Fine Tuning là một kỹ thuật Transfer Learning mà ! Hãy cùng tìm hiểu xem cụ thể nó là thế nào nhé.

    Khi mô hình của bạn đã hội tụ trên dữ liệu mới, bạn có thể cố gắng giải phóng toàn bộ hoặc một phần của mô hình cơ sở và đào tạo lại toàn bộ mô hình từ đầu đến cuối với tỷ lệ học tập rất thấp.

    Đây là bước cuối cùng tùy chọn có thể mang lại cho bạn những cải tiến gia tăng. Nó cũng có thể dẫn đến tình trạng overfitting – hãy cân nhắc điều đó.

    Điều quan trọng là chỉ thực hiện bước này sau khi mô hình với các lớp đông lạnh đã được huấn luyện để hội tụ. Nếu bạn trộn các lớp trainable được khởi tạo ngẫu nhiên với các lớp trainable chứa các tính năng đã được huấn luyện trước, các lớp được khởi tạo ngẫu nhiên sẽ gây ra các cập nhật gradient rất lớn trong quá trình huấn luyện, điều này sẽ phá hủy các tính năng đã được huấn luyện trước của bạn.

    Một vấn đề quan trọng nữa là là sử dụng tỷ lệ học tập rất thấp ở giai đoạn này, bởi vì bạn đang đào tạo một mô hình lớn hơn nhiều so với trong vòng đào tạo đầu tiên, trên một tập dữ liệu thường rất nhỏ. Do đó, bạn có nguy cơ bị overfitting rất nhanh nếu áp dụng các biện pháp cập nhật trọng lượng lớn. Ở đây, bạn chỉ muốn đọc các trọng số được huấn luyện trước theo cách tăng dần.

    Đây là cách implement fine-tuning toàn bộ mô hình cơ sở:

    # Hủy đóng băng mô hình cơ sở
    base_model.trainable = True
    
    # Quan trọng là phải biên dịch lại mô hình của bạn sau khi thực hiện bất kỳ thay đổi nào đối với thuộc tính `trainable` của bất kỳ lớp bên trong nào
    # Để các thay đổi của bạn được tính đến
    model.compile(optimizer=keras.optimizers.Adam(1e-5),  # Tỉ lệ học rất thấp
                  loss=keras.losses.BinaryCrossentropy(from_logits=True),
                  metrics=[keras.metrics.BinaryAccuracy()])
    
    # Train. Cẩn thận để dừng lại trước khi bị overfit
    model.fit(new_dataset, epochs=10, callbacks=..., validation_data=...)
    

    Lưu ý quan trọng về compile()trainable

    Việc gọi compile() trên một mô hình có nghĩa là "đóng băng" hành vi của mô hình đó. Điều này ngụ ý rằng các giá trị thuộc tính trainable tại thời điểm mô hình được biên dịch nên được bảo toàn trong suốt thời gian tồn tại của mô hình đó, cho đến khi quá trình biên dịch được gọi lại. Do đó, nếu bạn thay đổi bất kỳ giá trị có thể đào tạo nào, hãy đảm bảo gọi lại compile () trên mô hình của bạn để các thay đổi của bạn được tính đến.

    Lưu ý quan trọng về lớp BatchNormalization

    Nhiều mô hình hình ảnh chứa các lớp BatchNormalization. Lớp đó là một trường hợp đặc biệt trên mọi số lượng có thể tưởng tượng được. Dưới đây là một số điều cần ghi nhớ.

    • BatchNormalization chứa 2 trọng lượng không thể đào tạo được cập nhật trong quá trình đào tạo. Đây là các biến theo dõi giá trị trung bình và phương sai của các yếu tố đầu vào.
    • Khi bạn đặt bn_layer.trainable = False, lớp BatchNormalization sẽ chạy ở chế độ suy luận và sẽ không cập nhật thống kê trung bình & phương sai của nó. Điều này không đúng với các lớp khác nói chung, vì khả năng tập tạ & chế độ suy luận / huấn luyện là hai khái niệm trực giao. Nhưng cả hai được gắn với nhau trong trường hợp của lớp BatchNormalization.
    • Khi bạn giải phóng một mô hình có chứa các lớp BatchNormalization để thực hiện tinh chỉnh, bạn nên giữ các lớp BatchNormalization ở chế độ suy luận bằng cách chuyển training = False khi gọi mô hình cơ sở. Nếu không, các bản cập nhật được áp dụng cho các trọng lượng không thể đào tạo sẽ đột ngột phá hủy những gì mà mô hình đã học được.

    Bạn sẽ thấy mẫu này hoạt động trong ví dụ end-to-end ở cuối hướng dẫn này.

    Transfer learning & fine-tuning với một vòng lặp đào tạo tùy chỉnh

    Nếu thay vì fit(), bạn đang sử dụng vòng lặp đào tạo cấp thấp của riêng mình, thì quy trình làm việc về cơ bản vẫn giữ nguyên. Bạn nên cẩn thận chỉ tính đến danh sách model.trainable_weights khi áp dụng cập nhật gradient:

    # Khởi tạo mô hình cơ sở
    base_model = keras.applications.Xception(
        weights='imagenet',
        input_shape=(150, 150, 3),
        include_top=False)
    # Đóng băng mô hình cơ sở
    base_model.trainable = False
    
    # Khởi tạo một mô hình mới on top.
    inputs = keras.Input(shape=(150, 150, 3))
    x = base_model(inputs, training=False)
    x = keras.layers.GlobalAveragePooling2D()(x)
    outputs = keras.layers.Dense(1)(x)
    model = keras.Model(inputs, outputs)
    
    loss_fn = keras.losses.BinaryCrossentropy(from_logits=True)
    optimizer = keras.optimizers.Adam()
    
    # Lặp lại các lô của tập dữ liệu.
    for inputs, targets in new_dataset:
        # Mở GradientTape.
        with tf.GradientTape() as tape:
            # Chuyển tiếp
            predictions = model(inputs)
            # Tính toán giá trị tổn thất cho lô này.
            loss_value = loss_fn(targets, predictions)
    
        # Lấy gradients với độ giảm của trọng số *trainable*.
        gradients = tape.gradient(loss_value, model.trainable_weights)
        # Cập nhật trọng số của mô hình
        optimizer.apply_gradients(zip(gradients, model.trainable_weights))
    

    Một ví dụ từ đầu đến cuối: tinh chỉnh mô hình phân loại hình ảnh trên tập dữ liệu mèo và chó

    Để củng cố những khái niệm này, hãy hướng dẫn bạn qua một ví dụ cụ thể về học tập và tinh chỉnh chuyển giao từ đầu đến cuối. Chúng tôi sẽ tải mô hình Xception, được đào tạo trước trên ImageNet và sử dụng nó trên tập dữ liệu phân loại Kaggle "mèo so với chó".

    Lấy dữ liệu

    Đầu tiên, hãy tìm nạp tập dữ liệu mèo và chó bằng TFDS. Nếu bạn có tập dữ liệu của riêng mình, có thể bạn sẽ muốn sử dụng tiện ích tf.keras.preprocessing.image_dataset_from_directory để tạo các đối tượng tập dữ liệu có nhãn tương tự từ một tập hợp các hình ảnh trên đĩa được lưu trữ vào các thư mục dành riêng cho lớp.

    Học chuyển giao hữu ích nhất khi làm việc với các tập dữ liệu rất nhỏ. Để giữ cho tập dữ liệu của chúng tôi nhỏ, chúng tôi sẽ sử dụng 40% dữ liệu đào tạo ban đầu (25.000 hình ảnh) để đào tạo, 10% để xác thực và 10% để kiểm tra.

    import tensorflow_datasets as tfds
    
    tfds.disable_progress_bar()
    
    train_ds, validation_ds, test_ds = tfds.load(
        "cats_vs_dogs",
        # Reserve 10% for validation and 10% for test
        split=["train[:40%]", "train[40%:50%]", "train[50%:60%]"],
        as_supervised=True,  # Include labels
    )
    
    print("Number of training samples: %d" % tf.data.experimental.cardinality(train_ds))
    print("Number of validation samples: %d" % tf.data.experimental.cardinality(validation_ds))
    print("Number of test samples: %d" % tf.data.experimental.cardinality(test_ds))
    
    Number of training samples: 9305
    Number of validation samples: 2326
    Number of test samples: 2326
    

    Đây là 9 hình ảnh đầu tiên trong tập dữ liệu đào tạo – như bạn có thể thấy, chúng đều có kích thước khác nhau.

    import matplotlib.pyplot as plt
    
    plt.figure(figsize=(10, 10))
    for i, (image, label) in enumerate(train_ds.take(9)):
        ax = plt.subplot(3, 3, i + 1)
        plt.imshow(image)
        plt.title(int(label))
        plt.axis("off")
    

    Chúng ta cũng có thể thấy rằng nhãn 1 là "chó" và nhãn 0 là "mèo".

    Chuẩn hóa dữ liệu

    Hình ảnh thô của có nhiều kích cỡ khác nhau. Ngoài ra, mỗi pixel bao gồm 3 giá trị integer 0 đến 255 (giá trị RGB). Đây không phải là một sự phù hợp tuyệt vời cho mạng nơ-ron. Chúng ta cần làm 2 việc:

    • Chuẩn hóa thành kích thước hình ảnh cố định. Chúng ta chọn 150×150.
    • Chuẩn hóa các giá trị pixel từ -1 đến 1. Chúng tôi sẽ thực hiện việc này bằng cách sử dụng lớp Chuẩn hóa như một phần của chính mô hình.

    Nói chung, bạn nên phát triển các mô hình lấy dữ liệu thô làm đầu vào, trái ngược với các mô hình lấy dữ liệu đã được xử lý trước. Lý do là, nếu mô hình của bạn yêu cầu dữ liệu được xử lý trước, bất kỳ khi nào bạn xuất mô hình của mình để sử dụng ở nơi khác (trong trình duyệt web, trong ứng dụng dành cho thiết bị di động), bạn sẽ cần phải thực hiện lại cùng một quy trình xử lý trước. Điều này trở nên rất phức tạp rất nhanh chóng. Vì vậy, chúng ta nên thực hiện ít tiền xử lý nhất có thể trước khi đưa vào mô hình.

    Ở đây, chúng ta sẽ thực hiện thay đổi kích thước hình ảnh trong đường ống dữ liệu (vì mạng nơ-ron sâu chỉ có thể xử lý các lô dữ liệu liền kề) và chúng tôi sẽ thực hiện điều chỉnh tỷ lệ giá trị đầu vào như một phần của mô hình, khi chúng tôi tạo nó.

    Hãy thay đổi kích thước hình ảnh thành 150×150:

    size = (150, 150)
    
    train_ds = train_ds.map(lambda x, y: (tf.image.resize(x, size), y))
    validation_ds = validation_ds.map(lambda x, y: (tf.image.resize(x, size), y))
    test_ds = test_ds.map(lambda x, y: (tf.image.resize(x, size), y))
    

    Bên cạnh đó, hãy tập hợp dữ liệu và sử dụng bộ nhớ đệm & tìm nạp trước để tối ưu hóa tốc độ tải.

    batch_size = 32
    
    train_ds = train_ds.cache().batch(batch_size).prefetch(buffer_size=10)
    validation_ds = validation_ds.cache().batch(batch_size).prefetch(buffer_size=10)
    test_ds = test_ds.cache().batch(batch_size).prefetch(buffer_size=10)
    

    Sử dụng tăng dữ liệu ngẫu nhiên

    Khi bạn không có tập dữ liệu hình ảnh lớn, bạn nên đưa tính đa dạng mẫu vào một cách giả tạo bằng cách áp dụng các phép biến đổi ngẫu nhiên nhưng thực tế cho hình ảnh huấn luyện, chẳng hạn như lật ngang ngẫu nhiên hoặc xoay ngẫu nhiên nhỏ. Điều này giúp mô hình hiển thị các khía cạnh khác nhau của dữ liệu đào tạo trong khi làm chậm quá trình overfitting.

    from tensorflow import keras
    from tensorflow.keras import layers
    
    data_augmentation = keras.Sequential(
        [layers.RandomFlip("horizontal"), layers.RandomRotation(0.1),]
    )
    

    Hãy hình dung hình ảnh đầu tiên của lô đầu tiên trông như thế nào sau nhiều lần biến đổi ngẫu nhiên:

    import numpy as np
    
    for images, labels in train_ds.take(1):
        plt.figure(figsize=(10, 10))
        first_image = images[0]
        for i in range(9):
            ax = plt.subplot(3, 3, i + 1)
            augmented_image = data_augmentation(
                tf.expand_dims(first_image, 0), training=True
            )
            plt.imshow(augmented_image[0].numpy().astype("int32"))
            plt.title(int(labels[0]))
            plt.axis("off")
    

    Xây dựng một mô hình

    Bây giờ chúng ta hãy xây dựng một mô hình theo kế hoạch chi tiết đã giải thích trước đó.

    Lưu ý rằng:

    • Thêm một lớp Rescaling để chia tỷ lệ các giá trị đầu vào (ban đầu trong phạm vi [0, 255]) thành phạm vi [-1, 1].
    • Thêm một lớp Dropout trước lớp phân loại, để chính quy hóa.
    • Đảm bảo training = False khi gọi mô hình cơ sở, để nó chạy ở chế độ suy luận, do đó thống kê batchnorm không được cập nhật ngay cả sau khi chúng tôi giải phóng mô hình cơ sở để fine-tuning.
    base_model = keras.applications.Xception(
        weights="imagenet",  # Load weights pre-trained on ImageNet.
        input_shape=(150, 150, 3),
        include_top=False,
    )  # Do not include the ImageNet classifier at the top.
    
    # Freeze the base_model
    base_model.trainable = False
    
    # Create new model on top
    inputs = keras.Input(shape=(150, 150, 3))
    x = data_augmentation(inputs)  # Apply random data augmentation
    
    # Pre-trained Xception weights requires that input be scaled
    # from (0, 255) to a range of (-1., +1.), the rescaling layer
    # outputs: `(inputs * scale) + offset`
    scale_layer = keras.layers.Rescaling(scale=1 / 127.5, offset=-1)
    x = scale_layer(x)
    
    # The base model contains batchnorm layers. We want to keep them in inference mode
    # when we unfreeze the base model for fine-tuning, so we make sure that the
    # base_model is running in inference mode here.
    x = base_model(x, training=False)
    x = keras.layers.GlobalAveragePooling2D()(x)
    x = keras.layers.Dropout(0.2)(x)  # Regularize with dropout
    outputs = keras.layers.Dense(1)(x)
    model = keras.Model(inputs, outputs)
    
    model.summary()
    
    Model: "model"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
    _________________________________________________________________
    sequential_3 (Sequential)    (None, 150, 150, 3)       0         
    _________________________________________________________________
    rescaling (Rescaling)        (None, 150, 150, 3)       0         
    _________________________________________________________________
    xception (Functional)        (None, 5, 5, 2048)        20861480  
    _________________________________________________________________
    global_average_pooling2d (Gl (None, 2048)              0         
    _________________________________________________________________
    dropout (Dropout)            (None, 2048)              0         
    _________________________________________________________________
    dense_7 (Dense)              (None, 1)                 2049      
    =================================================================
    Total params: 20,863,529
    Trainable params: 2,049
    Non-trainable params: 20,861,480
    _________________________________________________________________
    

    Đào tạo lớp trên cùng

    model.compile(
        optimizer=keras.optimizers.Adam(),
        loss=keras.losses.BinaryCrossentropy(from_logits=True),
        metrics=[keras.metrics.BinaryAccuracy()],
    )
    
    epochs = 20
    model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
    
    Epoch 1/20
    291/291 [==============================] - 133s 451ms/step - loss: 0.1670 - binary_accuracy: 0.9267 - val_loss: 0.0830 - val_binary_accuracy: 0.9716
    Epoch 2/20
    291/291 [==============================] - 135s 465ms/step - loss: 0.1208 - binary_accuracy: 0.9502 - val_loss: 0.0768 - val_binary_accuracy: 0.9716
    Epoch 3/20
    291/291 [==============================] - 135s 463ms/step - loss: 0.1062 - binary_accuracy: 0.9572 - val_loss: 0.0757 - val_binary_accuracy: 0.9716
    Epoch 4/20
    291/291 [==============================] - 137s 469ms/step - loss: 0.1024 - binary_accuracy: 0.9554 - val_loss: 0.0733 - val_binary_accuracy: 0.9725
    Epoch 5/20
    291/291 [==============================] - 137s 470ms/step - loss: 0.1004 - binary_accuracy: 0.9587 - val_loss: 0.0735 - val_binary_accuracy: 0.9729
    Epoch 6/20
    291/291 [==============================] - 136s 467ms/step - loss: 0.0979 - binary_accuracy: 0.9577 - val_loss: 0.0747 - val_binary_accuracy: 0.9708
    Epoch 7/20
    291/291 [==============================] - 134s 462ms/step - loss: 0.0998 - binary_accuracy: 0.9596 - val_loss: 0.0706 - val_binary_accuracy: 0.9725
    Epoch 8/20
    291/291 [==============================] - 133s 457ms/step - loss: 0.1029 - binary_accuracy: 0.9592 - val_loss: 0.0720 - val_binary_accuracy: 0.9733
    Epoch 9/20
    291/291 [==============================] - 135s 466ms/step - loss: 0.0937 - binary_accuracy: 0.9625 - val_loss: 0.0707 - val_binary_accuracy: 0.9721
    Epoch 10/20
    291/291 [==============================] - 137s 472ms/step - loss: 0.0967 - binary_accuracy: 0.9580 - val_loss: 0.0720 - val_binary_accuracy: 0.9712
    Epoch 11/20
    291/291 [==============================] - 135s 463ms/step - loss: 0.0961 - binary_accuracy: 0.9612 - val_loss: 0.0802 - val_binary_accuracy: 0.9699
    Epoch 12/20
    291/291 [==============================] - 134s 460ms/step - loss: 0.0963 - binary_accuracy: 0.9638 - val_loss: 0.0721 - val_binary_accuracy: 0.9716
    Epoch 13/20
    291/291 [==============================] - 136s 468ms/step - loss: 0.0925 - binary_accuracy: 0.9635 - val_loss: 0.0736 - val_binary_accuracy: 0.9686
    Epoch 14/20
    291/291 [==============================] - 138s 476ms/step - loss: 0.0909 - binary_accuracy: 0.9624 - val_loss: 0.0766 - val_binary_accuracy: 0.9703
    Epoch 15/20
    291/291 [==============================] - 136s 467ms/step - loss: 0.0949 - binary_accuracy: 0.9598 - val_loss: 0.0704 - val_binary_accuracy: 0.9725
    Epoch 16/20
    291/291 [==============================] - 133s 456ms/step - loss: 0.0969 - binary_accuracy: 0.9586 - val_loss: 0.0722 - val_binary_accuracy: 0.9708
    Epoch 17/20
    291/291 [==============================] - 135s 464ms/step - loss: 0.0913 - binary_accuracy: 0.9635 - val_loss: 0.0718 - val_binary_accuracy: 0.9716
    Epoch 18/20
    291/291 [==============================] - 137s 472ms/step - loss: 0.0915 - binary_accuracy: 0.9639 - val_loss: 0.0727 - val_binary_accuracy: 0.9725
    Epoch 19/20
    291/291 [==============================] - 134s 460ms/step - loss: 0.0938 - binary_accuracy: 0.9631 - val_loss: 0.0707 - val_binary_accuracy: 0.9733
    Epoch 20/20
    291/291 [==============================] - 134s 460ms/step - loss: 0.0971 - binary_accuracy: 0.9609 - val_loss: 0.0714 - val_binary_accuracy: 0.9716
    
    <keras.callbacks.History at 0x7f4494e38f70>
    

    Thực hiện một vòng tinh chỉnh toàn bộ mô hình

    Cuối cùng, hãy giải phóng mô hình cơ sở và đào tạo toàn bộ mô hình từ đầu đến cuối với tỷ lệ học tập thấp.

    Quan trọng là, mặc dù mô hình cơ sở trở nên có thể huấn luyện được, nhưng nó vẫn đang chạy ở chế độ suy luận vì chúng ta đã đặt training=False khi gọi nó khi chúng ta xây dựng mô hình. Điều này có nghĩa là các lớp chuẩn hóa hàng loạt bên trong sẽ không cập nhật thống kê hàng loạt của chúng. Nếu họ làm vậy, họ sẽ phá hủy các đại diện mà mô hình đã học cho đến nay.

    base_model.trainable = True
    model.summary()
    
    model.compile(
        optimizer=keras.optimizers.Adam(1e-5),  # Low learning rate
        loss=keras.losses.BinaryCrossentropy(from_logits=True),
        metrics=[keras.metrics.BinaryAccuracy()],
    )
    
    epochs = 10
    model.fit(train_ds, epochs=epochs, validation_data=validation_ds)
    
    Model: "model"
    _________________________________________________________________
    Layer (type)                 Output Shape              Param #   
    =================================================================
    input_5 (InputLayer)         [(None, 150, 150, 3)]     0         
    _________________________________________________________________
    sequential_3 (Sequential)    (None, 150, 150, 3)       0         
    _________________________________________________________________
    rescaling (Rescaling)        (None, 150, 150, 3)       0         
    _________________________________________________________________
    xception (Functional)        (None, 5, 5, 2048)        20861480  
    _________________________________________________________________
    global_average_pooling2d (Gl (None, 2048)              0         
    _________________________________________________________________
    dropout (Dropout)            (None, 2048)              0         
    _________________________________________________________________
    dense_7 (Dense)              (None, 1)                 2049      
    =================================================================
    Total params: 20,863,529
    Trainable params: 20,809,001
    Non-trainable params: 54,528
    _________________________________________________________________
    Epoch 1/10
    291/291 [==============================] - 567s 2s/step - loss: 0.0749 - binary_accuracy: 0.9689 - val_loss: 0.0605 - val_binary_accuracy: 0.9776
    Epoch 2/10
    291/291 [==============================] - 551s 2s/step - loss: 0.0559 - binary_accuracy: 0.9770 - val_loss: 0.0507 - val_binary_accuracy: 0.9798
    Epoch 3/10
    291/291 [==============================] - 545s 2s/step - loss: 0.0444 - binary_accuracy: 0.9832 - val_loss: 0.0502 - val_binary_accuracy: 0.9807
    Epoch 4/10
    291/291 [==============================] - 558s 2s/step - loss: 0.0365 - binary_accuracy: 0.9874 - val_loss: 0.0506 - val_binary_accuracy: 0.9807
    Epoch 5/10
    291/291 [==============================] - 550s 2s/step - loss: 0.0276 - binary_accuracy: 0.9890 - val_loss: 0.0477 - val_binary_accuracy: 0.9802
    Epoch 6/10
    291/291 [==============================] - 588s 2s/step - loss: 0.0206 - binary_accuracy: 0.9916 - val_loss: 0.0444 - val_binary_accuracy: 0.9832
    Epoch 7/10
    291/291 [==============================] - 542s 2s/step - loss: 0.0206 - binary_accuracy: 0.9923 - val_loss: 0.0502 - val_binary_accuracy: 0.9828
    Epoch 8/10
    291/291 [==============================] - 544s 2s/step - loss: 0.0153 - binary_accuracy: 0.9939 - val_loss: 0.0509 - val_binary_accuracy: 0.9819
    Epoch 9/10
    291/291 [==============================] - 548s 2s/step - loss: 0.0156 - binary_accuracy: 0.9934 - val_loss: 0.0610 - val_binary_accuracy: 0.9807
    Epoch 10/10
    291/291 [==============================] - 546s 2s/step - loss: 0.0176 - binary_accuracy: 0.9936 - val_loss: 0.0561 - val_binary_accuracy: 0.9789
    
    <keras.callbacks.History at 0x7f4495056040> 
    

    Sau 10 epochs, fine-tuning mang lại cho chúng ta một cải tiến tốt đẹp ở đây.

    Kết bài

    Trên đây chúng ta đã tìm hiểu kỹ thuật Fine-tuning. Cảm ơn các bạn đã giành thời gian theo dõi. Thân ái !

    Tham khảo https://keras.io/guides/

  • Giới thiệu về Transfer learning và Fine-tuning (Phần 1)

    Giới thiệu về Transfer learning

    Mở đầu

    Trong quá trình xây dựng một mô hình học máy, chắc hẳn các bạn đã gặp phải một số vấn đề như mô hình dự đoán có độ chính xác thấp dù đã dùng một kiến trúc phức tạp, hay lượng dữ liệu quá ít để có thể huấn luyện một mô hình hoàn chỉnh. Thông thường, một mô hình có kết quả dự báo kém là do một số nguyên nhân sau

    • Dữ liệu nhỏ không đại diện: Bộ dữ liệu của chúng ta có kích thước quá bé so với mô hình được huấn luyện, khiến cho mô hình không học được các đặc trưng của ảnh để giải quyết các bài toán cụ thể như phân loại, nhận dạng, …

    • Mô hình mất cân bằng dữ liệu: Khi mà tập dữ liệu của chúng ta có sự chênh lệch lớn giữa các nhóm, ví dụ như chỉ có 100 ảnh cho con chó và 100.000 ảnh cho con mèo, tất nhiên mô hình sẽ “thiên vị” dự đoán nghiêng về con mèo nhiều hơn

    • Kiến trúc mô hình quá phức tạp: Khi ta có bộ dữ liệu lớn tới vài trăm triệu ảnh thì tất nhiên kiến trúc mô hình phức tạp có thể mang lại độ chính xác cao. Tuy nhiên đối với những bộ dữ liệu nhỏ, vừa phải thì mô hình quá phức tạp lại đem lại độ chính xác không cao. Cần chọn kiến trúc mô hình phù hợp với lượng data chúng ta làm việc cùng

    • Quá trình tối ưu hóa gặp khó khăn: Có thể các hyperparameter được thiết lập chưa tốt như learning rate khiến cho mô hình huấn luyện lâu hội tụ hoặc chưa đạt tới điểm global optimal

    Vậy khi chúng ta có một lượng data nhỏ nhưng muốn hoàn thiện một bài toán sử dụng mô hình hoàn chỉnh, làm thế nào để mô hình đó hoạt động tốt? Transfer Learning có thế giải quyết điều đó.

    Introduction

    Transfer learning – Học chuyển giao bao gồm việc sử dụng các tính năng đã học về một vấn đề và tận dụng chúng vào một vấn đề mới nhưng tương tự. Ví dụ, các tính năng từ một mô hình đã học để xác định các loài chim có thể hữu ích để khởi động một mô hình dùng để xác định tanukis(1 loài lửng của Nhật Bản).

    Học chuyển giao thường được thực hiện cho các nhiệm vụ mà tập dữ liệu của bạn có quá ít dữ liệu để đào tạo một mô hình quy mô đầy đủ từ đầu.

    Hiện thân phổ biến nhất của học chuyển tiếp trong học sâu là quy trình làm việc sau:

    • Lấy các lớp từ một mô hình đã được đào tạo trước đó.
    • Đóng băng(Freeze) chúng, để tránh phá hủy bất kỳ thông tin nào mà chúng chứa trong các đợt huấn luyện trong tương lai.
    • Thêm một số lớp mới, có thể đào tạo lên trên các lớp đã đóng băng. Chúng sẽ học cách biến các tính năng cũ thành dự đoán trên một tập dữ liệu mới.
    • Đào tạo các lớp mới trên tập dữ liệu của bạn.

    Bước cuối cùng (tùy chọn), là tinh chỉnh, bao gồm việc mở toàn bộ mô hình bạn đã thu được ở trên (hoặc một phần của nó) và đào tạo lại nó trên dữ liệu mới với tỷ lệ học tập rất thấp. Điều này có thể đạt được những cải tiến có ý nghĩa, bằng cách từng bước điều chỉnh các tính năng được đào tạo trước cho phù hợp với dữ liệu mới.

    Đầu tiên, chúng ta sẽ xem xét chi tiết về API có thể train của Keras, làm cơ sở cho hầu hết các quy trình học tập và tinh chỉnh chuyển giao.

    Sau đó, chúng tôi sẽ chứng minh quy trình làm việc điển hình bằng cách lấy một mô hình được đào tạo trước trên tập dữ liệu ImageNet và đào tạo lại nó trên tập dữ liệu phân loại Kaggle "mèo vs chó".

    Điều này được điều chỉnh từ Deep Learning với Python và bài đăng trên blog năm 2016 "xây dựng các mô hình phân loại hình ảnh mạnh mẽ bằng cách sử dụng rất ít dữ liệu".

    Các lớp đóng băng: hiểu thuộc tính trainable (có thể đào tạo)

    Các lớp và mô hình có ba thuộc tính trọng số:

    • weight (trọng số) : danh sách tất cả các biến trọng số của lớp.
    • trainable_weights (trọng số có thể đào tạo) : danh sách những thứ cần được cập nhật (thông qua gradient descent) để giảm thiểu tổn thất trong quá trình đào tạo.
    • non_trainable_weights (trọng số không thể đào tạo): là danh sách những thứ không được đào tạo. Thông thường, chúng được cập nhật bởi mô hình trong quá trình chuyển tiếp.

    Ví dụ : lớp Dense có 2 trainable_weights (kernel & bias)

    layer = keras.layers.Dense(3)
    layer.build((None, 4))  # Khởi tạo trọng số
    
    print("weights:", len(layer.weights))
    print("trainable_weights:", len(layer.trainable_weights))
    print("non_trainable_weights:", len(layer.non_trainable_weights))
    
    weights: 2
    trainable_weights: 2
    non_trainable_weights: 0
    

    Nói chung, tất cả các trọng số đều có thể huấn luyện được. Lớp tích hợp duy nhất có trọng số không thể đào tạo là lớp BatchNormalization. Nó sử dụng trọng số không thể đào tạo để theo dõi giá trị trung bình và phương sai của các đầu vào trong quá trình đào tạo. Để tìm hiểu cách sử dụng trọng số không thể đào tạo trong các lớp tùy chỉnh của riêng bạn, hãy xem hướng dẫn viết các lớp mới từ đầu.

    Ví dụ: lớp BatchNormalization có 2 trainable_weights và 2 non_trainable_weights

    layer = keras.layers.BatchNormalization()
    layer.build((None, 4))  # Khởi tạo trọng số
    
    print("weights:", len(layer.weights))
    print("trainable_weights:", len(layer.trainable_weights))
    print("non_trainable_weights:", len(layer.non_trainable_weights))
    
    weights: 4
    trainable_weights: 2
    non_trainable_weights: 2
    

    Các lớp và mô hình cũng có thuộc tính boolean có thể đào tạo. Giá trị của nó có thể được thay đổi. Đặt layer.trainable thành False sẽ di chuyển tất cả trọng lượng của lớp từ có thể huấn luyện sang không thể huấn luyện. Đây được gọi là "đóng băng" lớp: trạng thái của lớp bị đóng băng sẽ không được cập nhật trong quá trình đào tạo (khi đào tạo với fit() hoặc khi đào tạo với bất kỳ vòng lặp tùy chỉnh nào dựa vào trainable_weights để áp dụng cập nhật gradient).

    Ví dụ: đặt trainable thành False

    layer = keras.layers.Dense(3)
    layer.build((None, 4))  # Khởi tạo trọng số
    layer.trainable = False  # Đóng băng layer
    
    print("weights:", len(layer.weights))
    print("trainable_weights:", len(layer.trainable_weights))
    print("non_trainable_weights:", len(layer.non_trainable_weights))
    
    weights: 2
    trainable_weights: 0
    non_trainable_weights: 2
    

    Khi trọng số trainable trở thành non-trainable, giá trị của nó sẽ không còn được cập nhật trong quá trình huấn luyện.

    # Tạo mô hình với 2 layer
    layer1 = keras.layers.Dense(3, activation="relu")
    layer2 = keras.layers.Dense(3, activation="sigmoid")
    model = keras.Sequential([keras.Input(shape=(3,)), layer1, layer2])
    
    # Đóng băng layer1
    layer1.trainable = False
    
    # Giữ lại một bản sao trọng số của layer1 để tham khảo sau này
    initial_layer1_weights_values = layer1.get_weights()
    
    # Huấn luyện mô hình
    model.compile(optimizer="adam", loss="mse")
    model.fit(np.random.random((2, 3)), np.random.random((2, 3)))
    
    # Kiểm tra trọng số của layer1 không hề thay đổi trong quá trình training
    final_layer1_weights_values = layer1.get_weights()
    np.testing.assert_allclose(
        initial_layer1_weights_values[0], final_layer1_weights_values[0]
    )
    np.testing.assert_allclose(
        initial_layer1_weights_values[1], final_layer1_weights_values[1]
    )
    
    1/1 [==============================] - 0s 333ms/step - loss: 0.1007
    

    Cài đặt đệ quy của thuộc tính trainable

    Nếu bạn đặt trainable = False trong một model hoặc một lớp có nhiều lớp con, tất cả lớp con sẽ trở thành non-trainable Ví dụ :

    inner_model = keras.Sequential(
        [
            keras.Input(shape=(3,)),
            keras.layers.Dense(3, activation="relu"),
            keras.layers.Dense(3, activation="relu"),
        ]
    )
    
    model = keras.Sequential(
        [keras.Input(shape=(3,)), inner_model, keras.layers.Dense(3, activation="sigmoid"),]
    )
    
    model.trainable = False  # Đóng băng model 
    
    assert inner_model.trainable == False  # Tất cả lớp thuộc `model` dều bị đóng băng
    assert inner_model.layers[0].trainable == False
    

    Transfer learning workflow

    Một workflow điển hình của transfer learning được thực thi trong Keras:

    1. Khởi tạo mô hình cơ sở và tải các trọng số đã được đào tạo trước vào đó.
    2. Cố định tất cả các lớp trong mô hình cơ sở bằng cách đặt trainable = False.
    3. Tạo một mô hình mới trên đầu ra của một (hoặc một số) lớp từ mô hình cơ sở.
    4. Train mô hình mới trên tập dữ liệu mới của bạn.

    Lưu ý rằng có thể là một quy trình thay thế nhẹ hơn :

    1. Khởi tạo mô hình cơ sở và tải các trọng số đã được đào tạo trước vào đó.
    2. Chạy tập dữ liệu mới của bạn thông qua nó và ghi lại kết quả của một (hoặc một số) lớp từ mô hình cơ sở. Đây được gọi là feature extraction.
    3. Sử dụng đầu ra đó làm dữ liệu đầu vào cho một mô hình mới nhỏ hơn.

    Một ưu điểm chính của quy trình làm việc thứ hai đó là bạn chỉ chạy mô hình cơ sở một lần trên dữ liệu của mình, thay vì một lần cho mỗi epoch đào tạo. Vì vậy, nó nhanh hơn và tiết kiệm tài nguyên hơn rất nhiều.

    Tuy nhiên, một vấn đề với quy trình làm việc thứ hai đó là nó không cho phép bạn tự động sửa đổi dữ liệu đầu vào của mô hình mới trong quá trình đào tạo, ví dụ như bắt buộc khi thực hiện tăng dữ liệu. Học chuyển giao thường được sử dụng cho các nhiệm vụ khi tập dữ liệu mới của bạn có quá ít dữ liệu để đào tạo mô hình quy mô đầy đủ từ đầu và trong các tình huống như vậy, việc tăng dữ liệu là rất quan trọng. Vì vậy, trong những gì tiếp theo, chúng ta sẽ tập trung vào quy trình làm việc đầu tiên.

    Đây là quy trình làm việc đầu tiên trong Keras:

    Đầu tiên, khởi tạo một mô hình cơ sở với các trọng lượng được đào tạo trước.

    base_model = keras.applications.Xception(
        weights='imagenet',  # Load trọng số pre-trained tại ImageNet.
        input_shape=(150, 150, 3),
        include_top=False)  # Không bao gồm lớp phân loại ImageNet ở trên cùng
    

    Sau đó, đóng băng mô hình cơ sở

    base_model.trainable = False
    

    Tạo một mô hình mới trên đầu trang.

    inputs = keras.Input(shape=(150, 150, 3))
    # Đảm bảo base_model đang chạy chế độ inference ở đây,
    # bằng cách sử dụng `training=False`. Điều này rất quan trọng cho fine-tuning, 
    # mà tôi sẽ nhắc tới ở phần sau
    x = base_model(inputs, training=False)
    # Chuyển đổi các thuộc tính cấu hình của `base_model.output_shape[1:]` thành vectors
    x = keras.layers.GlobalAveragePooling2D()(x)
    # Một bộ phân loại Dense với một đơn vị duy nhất (phân loại nhị phân)
    outputs = keras.layers.Dense(1)(x)
    model = keras.Model(inputs, outputs)
    

    Train model với dữ liệu mới

    model.compile(optimizer=keras.optimizers.Adam(),
                  loss=keras.losses.BinaryCrossentropy(from_logits=True),
                  metrics=[keras.metrics.BinaryAccuracy()])
    model.fit(new_dataset, epochs=20, callbacks=..., validation_data=...)
    

    Kết luận

    Trên đây là tổng quan về Transfer Learning. Ở bài viết tiếp theo chúng ta sẽ tìm hiểu về Fine-tuning, một kỹ thuật Transfer Leaning.

    Thanks for reading

    Tham khảo https://keras.io/guides/

  • Tìm hiểu về Regular Expression

    Tìm hiểu về Regular Expression

    Tìm hiểu về Regular Expression

    Mở đầu

    RegEx là một khái niệm chúng ta thường xuyên gặp qua. Các master thì sẽ chẳng lạ lùng gì, còn với newbie thì cực kỳ khó hiểu và tiếp cận.

    Bài viết này mình sẽ giới thiệu qua về RegEx. Khi thành thạo được công cụ này, chắc chắn cuộc sống của lập trình viên sẽ "tươi đẹp" hơn rất nhiều.

    RegEx là gì ?

    RegEx (Regular Expression) trong tiếng Việt được gọi là Biểu thức chính quy. Regex không phải là một ngôn ngữ lập trình, nó chỉ là một bộ cú pháp dùng để bắt chuỗi. Regex là các ký tự được kết hợp với nhau theo quy tắc để tạo nên một trình tự giúp chúng ta tìm kiếm và thay thế văn bản một cách thông minh, nhanh chóng, đơn giản và thuận tiện. Nó có thể dùng được trong hầu hết các ngôn ngữ lập trình bậc cao như Java, C#, Python, JS, PHP,…

    Ứng dụng của Regular Expression

    • Ứng dụng trong kiểm tra tính hợp lệ
      • Kiểm tra email có hợp lệ hay không
      • Kiểm tra số điện thoại ở Việt Nam
      • Kiểm tra URL hợp lệ
      • Kiểm tra độ dài của câu có nằm trong khoảng (a,b) hay không
      • Bất cứ cái gì có quy tắc bạn đều có thể kiểm tra với Regex
    • Ứng dụng trong tìm kiếm và thay thế

    Cú pháp của biểu thức chính quy

    Chuỗi so khớp cơ bản

    Chuỗi Ý nghĩa
    . Khớp bất kỳ ký tự nào
    \d Khớp với số bất kỳ từ 0 – 9
    \D Phủ định của \d
    \w Khớp với các chữ cái tiếng anh, chữ số và dấu _
    \W Phủ định của \w
    <dấu cách> Khớp với dấu cách(SPACE trên bàn phím)
    \t Khớp với dấu tab
    \n Khớp với new line(xuống hàng)
    \s Khớp với dấu trắng bất kỳ(dấu cách, \t,\n)
    \S Phủ định của \s

    Kết hợp các chuỗi so khớp

    Bạn có thể kết hợp các chuỗi so khớp lại với nhau bằng cách đưa chúng vào trong cặp ngoặc vuông. Ví dụ :

    • [abc] -> Khớp các ký tự hoặc là a, hoặc là b, hoặc là c
    • [a-fA-Z] -> a-f là tất cả các ký tự từ a đến f trong bảng chữ cái tiếng anh đó, A-Z tương tự là từ A hoa đến Z hoa. Vậy là regex này khớp với mọi ký tự trong bảng chữ cái tiếng anh bất kể hoa thường.
    • [\d,] -> Khớp với ký tự số hoặc dấu ,

    Các ký tự ranh giới

    Ký tự Ý nghĩa Demo
    \b Xác định ranh giới của từ demo
    \B Phủ định của \b demo
    ^ Xác định vị trí bắt đầu dòng demo
    $ Xác định vị trí kết thúc dòng demo

    Sử|+ dụng hoặc trong regex

    (0|84|+84) : Hoặc 0, hoặc 84, hoặc +84 – demo

    Các ký tự định lượng

    Loại định lượng Ý nghĩa Demo
    X* So khớp lặp lại regex X 0 hoặc vô số lần demo
    X+ So khớp lặp lại regex X 1 hoặc vô số lần demo
    X? So khớp lặp lại regex X 0 hoặc 1 lần demo
    X{m} So khớp lặp lại regex X chính xác m lần demo
    X{m,} So khớp lặp lại regex X m hoặc nhiều hơn m lần demo
    X{m,n} So khớp lặp lại regex X với số lần từ m tới n(bao gồm cả m và n) demo

    Và một số ví dụ sau:

    • ab+ : khớp các chuỗi ab, abb, abbaabab,…
    • (ab)+ : khớp các chuỗi ab, abab, ababab,…

    Các ký tự đặc biệt

    Các ký tự {}[]()^$.|*+?\ và dấu - ở trong cặp ngoặc vuông là các ký tự đặc biệt. Nếu bạn muốn dùng nó để so khớp thì cần thêm dấu \ vào đằng trước:

    Ví dụ: \. sẽ khớp với dấu chấm .\\ sẽ khớp với ký tự \.

    Một số RegEx được dùng phổ biến

    So khớp email

    • ^\w+@[a-zA-Z_]+?\.[a-zA-Z]{2,3}$
    • ^[\w-\.]+@([\w-]+\.)+[\w-]{2,4}$
    • ^([a-zA-Z0-9_\-\.]+)@((\[[0-9]{1,3}\.[0-9]{1,3}\.[0-9]{1,3}\.)|((a-zA-Z0-9\-]+\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\]?)$
    • ^\w+[\w-\.]*\@\w+((-\w+)|(\w*))\.[a-z]{2,3}$
    • ^.+@.+$

    So khớp URL

    • ^((https?|ftp|file):\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?$
    • ((mailto\:|(news|(ht|f)tp(s?))\://){1}\S+)
    • (http|ftp|https):\/\/[\w\-_]+(\.[\w\-_]+)+([\w\-\.,@?^=%&amp;:/~\+#]*[\w\-\@?^=%&amp;/~\+#])?
    • ^(http|https|ftp)\://[a-zA-Z0-9\-\.]+\.[a-zA-Z]{2,3}(:[a-zA-Z0-9]*)?/?([a-zA-Z0-9\-\._\?\,\’/\\\+&amp;%\$#\=~])*$

    So khớp SĐT ở Việt Nam

    • \+?(0|84)\d{9}

    So khớp số nguyên

    • \b\d+\b
    • \b(?:\d{3}\.)+\d{3}\bdemo

    So khớp mã HTML

    So khớp tên riêng

    • (?:[A-Z]\p{L}+ ){1,3}[A-Z]\p{L}+demo

    Một số liên kết hữu ích

    1. Test RegEx online: https://regex101.com/
    2. RegEx cheetsheet: http://web.mit.edu/hackl/www/lab/turkshop/slides/regex-cheatsheet.pdf
    3. Thư viện regex: http://regexlib.com/

    Kết bài

    Trên đây là một số kiến thức "nhập môn" về RegEx. Hi vọng bài viết nhỏ này đã giúp bạn học được cú pháp viết RegEx và áp dụng vào công việc thường ngày.

  • 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/)