在本單元中,您將使用內建的 Amazon SageMaker k-Nearest Neighbor (k-NN) 演算法來訓練內容推薦模型。

Amazon SageMaker K-Nearest Neighbor (k-NN) 是一種非參數、索引型監督學習演算法,可用於分類和迴歸任務。對於分類,該演算法查詢目標的 K 個最近點,並傳回其類中最常用的標籤作為預測標籤。對於迴歸問題,該演算法傳回 K 個最近芳鄰傳回的預測平均值。

使用 k-NN 演算法訓練包括三個步驟:取樣、降維和建立索引。取樣會減小初始資料集的大小,以便適合記憶體。對於降維,該演算法減小資料的特徵維度,以減少記憶體中 k-NN 模型的佔用量和推論延遲。我們提供兩種降維方法:隨機投影和快速 Johnson-Lindenstrauss 轉換。通常,針對高維 (d >1000) 資料集使用降維可避免「維度詛咒」,該問題將影響隨維度增加而變得稀疏的資料統計分析。k-NN 訓練的主要目標是建構索引。該索引可有效查詢尚未確定其值或類別標籤點之間的距離,以及可用於推論的 K 個最近點。

在以下步驟中,對訓練任務指定 k-NN 演算法,設定超參數值以調整模型,然後執行模型。然後,將模型部署至由 Amazon SageMaker 管理的端點以進行預測。

完成單元的時間:20 分鐘


  • 步驟 1.建立並執行訓練任務

    在上一單元中,您建立了主題向量。在本單元中,您將建置和部署內容推薦單元,該單元將保留主題向量的索引。

    首先,建立字典,將經過重新整理的標籤連結至訓練資料中的原始標籤。在筆記本中,複製並貼上以下程式碼,然後選擇執行

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

    接著,使用以下程式碼將訓練資料存放在 S3 儲存貯體中:

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

    接下來,使用以下協助程式函數來建立 k-NN 估算器,就像在單元 3 中建立的 NTM 估算器一樣。

    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)
    

    在執行訓練任務時,請仔細查看協助程式函數中的參數。

    Amazon SageMaker k-NN 演算法提供許多不同的距離指標,來計算最近芳鄰。在自然語言處理中使用的一種常用指標是餘弦距離。數學上,兩個向量 A 和 B 之間的餘弦「相似度」由以下方程式得出:

    透過將 index_metric 設定為 COSINE,Amazon SageMaker 會自動使用餘弦相似度來計算最近芳鄰。預設距離為 L2 範數,這是標準的歐幾里得距離。請注意,在發佈時,僅 faiss.IVFFlat 索引類型,而非 faiss.IVFPQ 索引方法支援 COSINE。

    您應會在終端機中看到以下輸出。

    Completed - Training job completed

    成功! 由於您希望該模型傳回指定的特定測試主題的最近鄰居,因此您需要將其部署為即時託管端點。

  • 步驟 2.部署內容推薦模型

    與使用 NTM 模型一樣,為 k-NN 模型定義以下協助程式函數以啟動端點。在協助程式函數中,接受字符 applications/jsonlines; verbose=true 顯示 k-NN 模型傳回所有​​餘弦距離,而不僅僅是最近芳鄰。若要建置推薦引擎,您需要獲取模型的前 K 個建議,為此您需要將 verbose 參數設定為 true,而非預設值 false。

    將以下程式碼複製並粘貼到筆記本中,然後選取執行

    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)

    接下來,對測試資料進行預處理,以便您可以執行推論。

    將以下程式碼複製並粘貼到筆記本中,然後選取執行

    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])       
    

    在本單元的最後一步,您將探索內容推薦模型。

  • 步驟 3.探索內容推薦模型

    現在,您已經獲得預測,可以將測試主題的主題分佈與 k-NN 模型推薦的最近 k 主題作比較。

    將以下程式碼複製並粘貼到筆記本中,然後選取執行

    # 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()
    

    執行以下程式碼以繪製主題分佈:

    plot_topic_distribution(18)
    

    現在,嘗試一些其他主題。執行以下程式碼儲存格:

    plot_topic_distribution(25)
    plot_topic_distribution(5000)

    根據您選取的主題數 (NUM_TOPICS),您的繪圖可能會有所差異。但總體而言,這些繪圖表明,透過 k-NN 模型使用餘弦相似度發現的最近鄰文件主題分佈與我們饋送至模型中的測試文件主題分佈非常相似。

    結果表明,k-NN 可能是建置語義型資訊擷取系統的不錯方法,其首先將文件內嵌至主題向量,然後使用 k-NN 模型來提供建議。


恭喜您! 在本單元中,您訓練、部署和探索了內容推薦模型。

在下一個單元中,您將清除在本實驗室中使用的資源。