Trong mô-đun này, bạn sẽ sử dụng Thuật toán lân cận k gần nhất (k-NN) Amazon SageMaker tích hợp để đào tạo mô hình đề xuất nội dung.

Lân cận K gần nhất (k-NN) Amazon SageMaker là một thuật toán học có giám sát, dựa trên chỉ mục và không cần tham số. Thuật toán này có thể được dùng để phân loại và hồi quy các nhiệm vụ. Để phân loại, thuật toán này sẽ truy vấn các điểm k gần nhất với mục tiêu và trả về nhãn dự đoán là nhãn thường gặp nhất của lớp chứa các điểm k đó. Đối với vấn đề hồi quy, thuật toán này trả về giá trị dự đoán trung bình mà các điểm lân cận k gần nhất trả về.

Quá trình đào tạo bằng thuật toán k-NN sẽ có 3 bước: lấy mẫu, giảm số chiều và dựng chỉ mục. Lấy mẫu sẽ giúp giảm thiểu kích thước của tập dữ liệu ban đầu để phù hợp với bộ nhớ. Để giảm số chiều, thuật toán sẽ làm giảm số chiều đặc trưng của dữ liệu để giảm thiểu dấu vết của mô hình k-NN trong bộ nhớ và độ trễ suy luận. Chúng tôi cung cấp 2 phương pháp giảm số chiều: chiếu ngẫu nhiên và chuyển đổi nhanh Johnson-Lindenstrauss. Thông thường, bạn sẽ muốn giảm số chiều cho các tập dữ liệu rất nhiều chiều (d >1000) để tránh “sự bùng nổ tổ hợp” gây khó khăn cho hoạt động phân tích thống kê những dữ liệu mà có nguy cơ trở nên thưa thớt khi số chiều tăng lên. Mục đích chính của việc đào tạo theo thuật toán k-NN là xây dựng chỉ mục. Chỉ mục giúp tra cứu một cách hiệu quả khoảng cách giữa các điểm có giá trị hoặc nhãn lớp chưa xác định được, cũng như các điểm k gần nhất cần dùng cho suy luận.

Trong các bước tiếp theo, bạn sẽ xác định thuật toán k-NN cho tác vụ đào tạo, đặt giá trị siêu tham số để tinh chỉnh mô hình và chạy mô hình. Sau đó, bạn sẽ triển khai mô hình cho một điểm cuối do Amazon SageMaker quản lý để đưa ra dự đoán.

Thời gian hoàn thành mô-đun: 20 phút


  • Bước 1. Tạo và chạy tác vụ đào tạo

    Trong mô-đun trước, bạn đã tạo véc-tơ chủ đề. Trong mô-đun này, bạn sẽ xây dựng và triển khai mô-đun đề xuất nội dung, giúp giữ lại chỉ mục của các véc-tơ chủ đề.

    Đầu tiên, hãy tạo một từ điển để liên kết nhãn xáo trộn với nhãn gốc trong dữ liệu đào tạo. Trong sổ ghi chép, hãy sao chép và dán đoạn mã sau rồi chọn Chạy.

    labels = newidx 
    labeldict = dict(zip(newidx,idx))

    Tiếp theo, lưu trữ dữ liệu đào tạo trong vùng lưu trữ S3 bằng cách dùng đoạn mã sau:

    import io
    import sagemaker.amazon.common as smac
    
    
    print('train_features shape = ', predictions.shape)
    print('train_labels shape = ', labels.shape)
    buf = io.BytesIO()
    smac.write_numpy_to_dense_tensor(buf, predictions, labels)
    buf.seek(0)
    
    bucket = BUCKET
    prefix = PREFIX
    key = 'knn/train'
    fname = os.path.join(prefix, key)
    print(fname)
    boto3.resource('s3').Bucket(bucket).Object(fname).upload_fileobj(buf)
    s3_train_data = 's3://{}/{}/{}'.format(bucket, prefix, key)
    print('uploaded training data location: {}'.format(s3_train_data))
    

    Sau đó, dùng hàm trợ giúp sau để tạo trình ước lượng k-NN tương tự như trình ước lượng NTM mà bạn đã tạo ở Mô-đun 3.

    def trained_estimator_from_hyperparams(s3_train_data, hyperparams, output_path, s3_test_data=None):
        """
        Create an Estimator from the given hyperparams, fit to training data, 
        and return a deployed predictor
        
        """
        # set up the estimator
        knn = sagemaker.estimator.Estimator(get_image_uri(boto3.Session().region_name, "knn"),
            get_execution_role(),
            train_instance_count=1,
            train_instance_type='ml.c4.xlarge',
            output_path=output_path,
            sagemaker_session=sagemaker.Session())
        knn.set_hyperparameters(**hyperparams)
        
        # train a model. fit_input contains the locations of the train and test data
        fit_input = {'train': s3_train_data}
        knn.fit(fit_input)
        return knn
    
    hyperparams = {
        'feature_dim': predictions.shape[1],
        'k': NUM_NEIGHBORS,
        'sample_size': predictions.shape[0],
        'predictor_type': 'classifier' ,
        'index_metric':'COSINE'
    }
    output_path = 's3://' + bucket + '/' + prefix + '/knn/output'
    knn_estimator = trained_estimator_from_hyperparams(s3_train_data, hyperparams, output_path)
    

    Khi tác vụ đào tạo đang chạy, hãy quan sát kỹ hơn các tham số trong hàm trợ giúp.

    Thuật toán Amazon SageMaker k-NN cung cấp nhiều số liệu khoảng cách khác nhau phục vụ việc tính toán các điểm lân cận gần nhất. Một số liệu phổ biến được dùng trong xử lý ngôn ngữ tự nhiên là khoảng cách cosine. Về mặt toán học, mức độ “tương đồng” cosine giữa 2 véc-tơ A và B được biểu diễn bằng hàm sau:

    Bằng cách đặt index_metric thành COSINE, Amazon SageMaker sẽ tự động sử dụng mức độ tương đồng cosine để tính toán các điểm lân cận gần nhất. Khoảng cách mặc định là L2 chuẩn. Đây là khoảng cách Euclid tiêu chuẩn. Hãy lưu ý rằng khi xuất bản, COSINE chỉ được hỗ trợ đối với loại chỉ mục faiss.IVFFlat chứ không được hỗ trợ đối với phương pháp lập chỉ mục faiss.IVFPQ.

    Bạn sẽ thấy kết quả sau đây trong cửa sổ dòng lệnh của mình.

    Completed - Training job completed

    Thành công rồi! Do bạn muốn mô hình này trả về các điểm lân cận gần nhất từ một chủ đề thử nghiệm cụ thể cho trước, nên bạn cần triển khai mô hình dưới dạng một điểm cuối lưu trữ trực tiếp.

  • Bước 2. Triển khai mô hình đề xuất nội dung

    Tương tự như với mô hình NTM, hãy xác định hàm trợ giúp sau đây cho mô hình k-NN để khởi chạy điểm cuối. Trong hàm trợ giúp, token chấp thuận applications/jsonlines; verbose=true sẽ cho mô hình k-NN biết là cần trả về mọi khoảng cách cosine thay vì chỉ trả về điểm lân cận gần nhất. Để xây dựng công cụ đề xuất, bạn phải lấy những điểm k tốt nhất mà mô hình gợi ý. Sau đó, bạn cần đặt tham số verbose thành true, thay vì giá trị mặc định là false.

    Sao chép và dán đoạn mã sau vào sổ ghi chép rồi chọn Chạy.

    def predictor_from_estimator(knn_estimator, estimator_name, instance_type, endpoint_name=None): 
        knn_predictor = knn_estimator.deploy(initial_instance_count=1, instance_type=instance_type,
                                            endpoint_name=endpoint_name,
                                            accept="application/jsonlines; verbose=true")
        knn_predictor.content_type = 'text/csv'
        knn_predictor.serializer = csv_serializer
        knn_predictor.deserializer = json_deserializer
        return knn_predictor
    import time
    
    instance_type = 'ml.m4.xlarge'
    model_name = 'knn_%s'% instance_type
    endpoint_name = 'knn-ml-m4-xlarge-%s'% (str(time.time()).replace('.','-'))
    print('setting up the endpoint..')
    knn_predictor = predictor_from_estimator(knn_estimator, model_name, instance_type, endpoint_name=endpoint_name)

    Tiếp đến, hãy xử lý sơ bộ dữ liệu thử nghiệm để có thể chạy suy luận.

    Sao chép và dán đoạn mã sau vào sổ ghi chép rồi chọn Chạy.

    def preprocess_input(text):
        text = strip_newsgroup_header(text)
        text = strip_newsgroup_quoting(text)
        text = strip_newsgroup_footer(text)
        return text    
        
    test_data_prep = []
    for i in range(len(newsgroups_test)):
        test_data_prep.append(preprocess_input(newsgroups_test[i]))
    test_vectors = vectorizer.fit_transform(test_data_prep)
    
    test_vectors = np.array(test_vectors.todense())
    test_topics = []
    for vec in test_vectors:
        test_result = ntm_predictor.predict(vec)
        test_topics.append(test_result['predictions'][0]['topic_weights'])
    
    topic_predictions = []
    for topic in test_topics:
        result = knn_predictor.predict(topic)
        cur_predictions = np.array([int(result['labels'][i]) for i in range(len(result['labels']))])
        topic_predictions.append(cur_predictions[::-1][:10])       
    

    Ở bước cuối cùng của mô-đun này, bạn sẽ khám phá mô hình đề xuất nội dung.

  • Bước 3. Khám phá mô hình đề xuất nội dung

    Lúc này, mô hình đã đưa ra các dự đoán. Bạn có thể lập biểu đồ phân phối chủ đề của chủ đề thử nghiệm so với các chủ đề k gần nhất mà mô hình k-NN đề xuất.

    Sao chép và dán đoạn mã sau vào sổ ghi chép rồi chọn Chạy.

    # set your own k.
    def plot_topic_distribution(topic_num, k = 5):
        
        closest_topics = [predictions[labeldict[x]] for x in topic_predictions[topic_num][:k]]
        closest_topics.append(np.array(test_topics[topic_num]))
        closest_topics = np.array(closest_topics)
        df = pd.DataFrame(closest_topics.T)
        df.rename(columns ={k:"Test Document Distribution"}, inplace=True)
        fs = 12
        df.plot(kind='bar', figsize=(16,4), fontsize=fs)
        plt.ylabel('Topic assignment', fontsize=fs+2)
        plt.xlabel('Topic ID', fontsize=fs+2)
        plt.show()
    

    Chạy đoạn mã sau để lập biểu đồ phân phối chủ đề:

    plot_topic_distribution(18)
    

    Bây giờ, hãy thử một số chủ đề khác. Chạy các ô mã lệnh sau đây:

    plot_topic_distribution(25)
    plot_topic_distribution(5000)

    Biểu đồ của bạn có thể phần nào đó khác nhau tùy theo số lượng chủ đề (NUM_TOPICS) mà bạn chọn. Tuy nhiên, về mặt tổng thể, những biểu đồ này sẽ cho thấy rằng sự phân phối chủ đề của các tài liệu lân cận gần nhất phát hiện được nhờ mức độ tương đồng Cosine của mô hình k-NN sẽ khá giống với phân phối chủ đề của tài liệu thử nghiệm mà chúng ta đã nạp vào mô hình.

    Các kết quả phần nào cho thấy rằng k-NN là một cách hữu hiệu để xây dựng hệ thống truy xuất thông tin theo ngữ nghĩa bằng cách nhúng các tài liệu vào véc-tơ chủ đề rồi dùng mô hình k-NN để phân phối các đề xuất.


Xin chúc mừng! Trong mô-đun này, bạn đã đào tạo, triển khai và khám phá mô hình đề xuất nội dung của mình.

Trong mô-đun tiếp theo, bạn sẽ dọn dẹp các tài nguyên đã tạo trong lab này.