Neste módulo, você usará o algoritmo integrado k-Nearest Neighbors (k-NN) do Amazon SageMaker para treinar o modelo de recomendações de conteúdo.

O K-Nearest Neighbors (k-NN) do Amazon SageMaker é um algoritmo de aprendizagem não paramétrico, baseado em índice e supervisionado que pode ser usado para tarefas de classificação e regressão. Para classificação, o algoritmo consulta os pontos k mais próximos do destino e retorna o rótulo mais frequentemente usado de sua classe como o rótulo previsto. Para problemas de regressão, o algoritmo retorna a média dos valores previstos retornados pelos vizinhos mais próximos de k.

O treinamento com o algoritmo k-NN tem três etapas: amostragem, redução de dimensão e criação de índice. A amostragem reduz o tamanho do conjunto de dados inicial para que ele caiba na memória. Para redução de dimensão, o algoritmo diminui a dimensão do recurso de dados para reduzir o espaço ocupado pelo modelo k-NN na latência da memória e inferência. Fornecemos dois métodos de redução de dimensão: projeção aleatória e a rápida transformação de Johnson-Lindenstrauss. Normalmente, a redução de dimensão para conjuntos de dados de alta dimensão (d > 1000) é usada para evitar a "maldição da dimensionalidade" que atrapalha a análise estatística dos dados que se tornam esparsos à medida que a dimensionalidade aumenta. O objetivo principal do treinamento de k-NN é criar o índice. O índice permite pesquisas eficientes de distâncias entre pontos cujos valores ou rótulos de classe ainda não foram determinados e os pontos mais próximos de k a serem usados para inferência.

Nas etapas a seguir, você especificará o algoritmo k-NN para o trabalho de treinamento, definirá os valores do hiperparâmetro para ajustar o modelo e executará o modelo. Em seguida, você implantará o modelo em um endpoint gerenciado pelo Amazon SageMaker para fazer previsões.

Tempo de conclusão do módulo: 20 minutos


  • Etapa 1. Crie e execute um trabalho de treinamento

    No módulo anterior, você criou vetores de tópicos. Neste módulo, você criará e implementará o módulo de recomendações de conteúdo que mantém um índice dos vetores de tópico.

    Primeiro, crie um dicionário que vincule os rótulos aleatórios aos rótulos originais nos dados de treinamento. No bloco de anotações do Jupyter, copie e cole o código a seguir e escolha Executar.

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

    Em seguida, armazene os dados de treinamento no bucket do S3 usando o seguinte código:

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

    Em seguida, use a função auxiliar a seguir para criar um estimador de k-NN muito parecido com o estimador de NTM que você criou no Módulo 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)
    

    Enquanto o trabalho de treinamento é executado, observe mais de perto os parâmetros da função auxiliar.

    O algoritmo k-NN do Amazon SageMaker oferece várias métricas de distância diferentes para calcular os vizinhos mais próximos. Uma métrica popular usada no processamento de linguagem natural é a distância do cosseno. Matematicamente, a “similaridade” do cosseno entre dois vetores A e B é calculada pela seguinte equação:

    Ao definir index_metric como COSSENO, o Amazon SageMaker usa automaticamente a semelhança de cosseno para calcular os vizinhos mais próximos. A distância padrão é a norma L2, que é a distância euclidiana padrão. Observe que, na publicação, o COSSENO é compatível somente com o tipo de índice faiss.IVFFlat e não com o método de indexação faiss.IVFPQ.

    A saída a seguir será exibida no terminal.

    Completed - Training job completed

    Êxito! Como você deseja que esse modelo retorne os vizinhos mais próximos com base em um tópico de teste específico, é necessário implantá-lo como um endpoint hospedado em tempo real.

  • Etapa 2. Implante o modelo de recomendações de conteúdo

    Assim como você fez com o modelo NTM, defina a função auxiliar a seguir para o modelo k-NN para iniciar o endpoint. Na função auxiliar, o token de aceitação applications/jsonlines; verbose=true diz ao modelo k-NN para retornar todas as distâncias do cosseno em vez de apenas o vizinho mais próximo. Para criar um mecanismo de recomendação, é necessário obter as sugestões mais elevadas de k por modelo,para as quais você precisa definir o parâmetro verbose como true, em vez do padrão, false.

    Copie e cole o código a seguir no bloco de anotações e escolha Executar.

    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)

    Em seguida, pré-processe os dados de teste para poder executar inferências.

    Copie e cole o código a seguir no bloco de anotações e escolha Executar.

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

    Na última etapa deste módulo, você explorará o modelo de recomendações de conteúdo.

  • Etapa 3. Explore o modelo de recomendações de conteúdo

    Agora que você obteve as previsões, poderá plotar as distribuições de tópicos dos tópicos de teste, em comparação com os tópicos mais próximos de k recomendados pelo modelo k-NN.

    Copie e cole o código a seguir no bloco de anotações e escolha Executar.

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

    Execute o seguinte código para plotar a distribuição de tópicos:

    plot_topic_distribution(18)
    

    Agora, tente alguns outros tópicos. Execute as seguintes células de código:

    plot_topic_distribution(25)
    plot_topic_distribution(5000)

    Seus gráficos podem parecer um pouco diferentes com base no número de tópicos (NUM_TOPICS) que você escolher. No geral, esses gráficos mostram que a distribuição de tópicos dos documentos vizinhos mais próximos encontrados usando a similaridade de Cosseno pelo modelo k-NN é bastante semelhante à distribuição de tópicos do documento de teste que inserimos no modelo.

    Os resultados sugerem que o k-NN pode ser uma boa maneira de criar um sistema de recuperação de informações baseado em semântica, primeiro incorporando os documentos em vetores de tópicos e, em seguida, usando um modelo de k-NN para oferecer recomendações.


Parabéns! Neste módulo, você treinou, implantou e explorou um modelo de recomendações de conteúdo.

No próximo módulo, você limpará os recursos usados neste laboratório.