Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Preço ideal para lucro máximo usando o Amazon SageMaker

Este é um post convidado de Viktor Enrico Jeney, engenheiro sênior de aprendizado de máquina da Adspert.

publicitário é um ISV ​​com sede em Berlim que desenvolveu uma ferramenta de gerenciamento de lances projetada para otimizar automaticamente o marketing de desempenho e campanhas publicitárias. O princípio central da empresa é automatizar a maximização do lucro da publicidade de comércio eletrônico com a ajuda da inteligência artificial. O desenvolvimento contínuo de plataformas de publicidade abre caminho para novas oportunidades, que a Adspert utiliza habilmente para o sucesso de seus clientes.

O objetivo principal do Adspert é simplificar o processo para os usuários enquanto otimiza campanhas publicitárias em diferentes plataformas. Isso inclui o uso de informações coletadas em várias plataformas equilibradas com o orçamento ideal definido em um nível acima de cada plataforma. O foco da Adspert é otimizar o alcance da meta do cliente, independentemente da plataforma utilizada. A Adspert continua a adicionar plataformas conforme necessário para oferecer vantagens significativas aos nossos clientes.

Neste post, compartilhamos como o Adspert criou a ferramenta de precificação do zero usando diferentes serviços da AWS, como Amazon Sage Maker e como o Adspert colaborou com o Laboratório de dados da AWS para acelerar este projeto desde a concepção até a construção em tempo recorde.

A ferramenta de preços reajusta o preço de um produto selecionado pelo vendedor em um mercado de comércio eletrônico com base na visibilidade e na margem de lucro para maximizar os lucros no nível do produto.

Como vendedor, é essencial que seus produtos estejam sempre visíveis, pois isso aumentará as vendas. O fator mais importante nas vendas de comércio eletrônico é simplesmente se sua oferta é visível para os clientes em vez da oferta de um concorrente.

Embora certamente dependa da plataforma de comércio eletrônico específica, descobrimos que o preço do produto é um dos números-chave mais importantes que podem afetar a visibilidade. No entanto, os preços mudam com frequência e rapidez; por isso, a ferramenta de precificação precisa atuar em tempo quase real para aumentar a visibilidade.

Visão geral da solução

O diagrama a seguir ilustra a arquitetura da solução.

A solução contém os seguintes componentes:

  1. Amazon Relational Database Service (Amazon RDS) para PostgreSQL é a principal fonte de dados, contendo informações do produto que são armazenadas em um banco de dados RDS for Postgres.
  2. As informações de alterações na lista de produtos chegam em tempo real em um Serviço de fila simples da Amazon (Amazon SQS) fila.
  3. As informações do produto armazenadas no Amazon RDS são ingeridas quase em tempo real na camada bruta usando o padrão change data capture (CDC) disponível em Serviço de migração de banco de dados AWS (AWS-DMS).
  4. As notificações de lista de produtos provenientes do Amazon SQS são ingeridas quase em tempo real na camada bruta usando um AWS Lambda função.
  5. Os dados de origem originais são armazenados no Serviço de armazenamento simples da Amazon (Amazon S3) bucket de camada bruta usando o formato de dados Parquet. Essa camada é a única fonte de verdade para o data lake. O particionamento usado neste armazenamento suporta o processamento incremental de dados.
  6. Cola AWS As tarefas de extração, transformação e carregamento (ETL) limpam os dados do produto, removendo duplicatas e aplicando consolidação de dados e transformações genéricas não vinculadas a um caso de negócios específico.
  7. A camada de estágio do Amazon S3 recebe dados preparados que são armazenados no formato Apache Parquet para processamento adicional. O particionamento usado no armazenamento de estágio oferece suporte ao processamento incremental de dados.
  8. Os trabalhos do AWS Glue criados nessa camada usam os dados disponíveis na camada de estágio do Amazon S3. Isso inclui a aplicação de regras de negócios específicas do caso de uso e cálculos necessários. Os dados de resultados desses trabalhos são armazenados na camada de análise do Amazon S3.
  9. A camada de análise do Amazon S3 é usada para armazenar os dados usados ​​pelos modelos de ML para fins de treinamento. O particionamento usado no armazenamento selecionado é baseado no uso de dados esperado. Isso pode ser diferente do particionamento usado na camada de palco.
  10. O modelo de ML de reprecificação é uma implementação Scikit-Learn Random Forest no SageMaker Script Mode, que é treinado usando dados disponíveis no bucket do S3 (a camada de análise).
  11. Um trabalho de processamento de dados do AWS Glue prepara os dados para a inferência em tempo real. A tarefa processa os dados ingeridos no bucket do S3 (camada de estágio) e invoca o endpoint de inferência do SageMaker. Os dados são preparados para serem usados ​​pelo modelo de reprecificação do SageMaker. O AWS Glue foi preferido ao Lambda, porque a inferência requer diferentes operações complexas de processamento de dados, como junções e funções de janela em um alto volume de dados (bilhões de transações diárias). O resultado das invocações do modelo de redefinição de preços é armazenado no bucket do S3 (camada de inferência).
  12. O trabalho de treinamento do SageMaker é implantado usando um ponto de extremidade do SageMaker. Esse endpoint é invocado pelo processador de inferência do AWS Glue, gerando recomendações de preços quase em tempo real para aumentar a visibilidade do produto.
  13. As previsões geradas pelo endpoint de inferência do SageMaker são armazenadas na camada de inferência do Amazon S3.
  14. A função do otimizador de previsões do Lambda processa as recomendações geradas pelo endpoint de inferência do SageMaker e gera uma nova recomendação de preço que se concentra em maximizar o lucro do vendedor, aplicando uma compensação entre o volume de vendas e a margem de vendas.
  15. As recomendações de preço geradas pelo otimizador de previsões do Lambda são submetidas à API de reprecificação, que atualiza o preço do produto no mercado.
  16. As recomendações de preço atualizadas geradas pelo otimizador de previsões do Lambda são armazenadas na camada de otimização do Amazon S3.
  17. O trabalho do carregador de previsão do AWS Glue recarrega no banco de dados SQL do RDS for Postgres de origem as previsões geradas pelo modelo de ML para fins de auditoria e relatórios. O AWS Glue Studio foi usado para implementar esse componente; é uma interface gráfica que facilita a criação, execução e monitoramento de trabalhos ETL no AWS Glue.

Preparação de dados

O conjunto de dados para o modelo de visibilidade do Adspert é criado a partir de uma fila SQS e ingerido na camada bruta do nosso data lake em tempo real com o Lambda. Depois, os dados brutos são higienizados realizando transformações simples, como a remoção de duplicatas. Esse processo é implementado no AWS Glue. O resultado é armazenado na camada de teste do nosso data lake. As notificações fornecem aos concorrentes de um determinado produto, com seus preços, canais de atendimento, prazos de entrega e muitas outras variáveis. Eles também fornecem uma medida de visibilidade dependente da plataforma, que pode ser expressa como uma variável booleana (visível ou não visível). Recebemos uma notificação sempre que uma mudança de oferta acontece, o que soma vários milhões de eventos por mês em todos os produtos de nossos clientes.

A partir desse conjunto de dados, extraímos os dados de treinamento da seguinte forma: para cada notificação, emparelhamos as ofertas visíveis com todas as ofertas não visíveis e vice-versa. Cada ponto de dados representa uma competição entre dois vendedores, na qual há um vencedor e um perdedor claros. Esse trabalho de processamento é implementado em um trabalho do AWS Glue com Spark. O conjunto de dados de treinamento preparado é enviado para o bucket analítico do S3 para ser usado pelo SageMaker.

Treine o modelo

Nosso modelo classifica para cada par de ofertas, se uma determinada oferta será visível. Este modelo permite-nos calcular o melhor preço para os nossos clientes, aumentar a visibilidade com base na concorrência e maximizar o seu lucro. Além disso, esse modelo de classificação pode nos fornecer insights mais profundos sobre os motivos pelos quais nossas listagens são visíveis ou não. Usamos os seguintes recursos:

  • Relação do nosso preço em relação aos preços dos concorrentes
  • Diferença nos canais de atendimento
  • Quantidade de feedback para cada vendedor
  • Avaliação de feedback de cada vendedor
  • Diferença nos tempos mínimos de envio
  • Diferença nos tempos máximos de envio
  • Disponibilidade do produto de cada vendedor

O Adspert usa o SageMaker para treinar e hospedar o modelo. Usamos a implementação Scikit-Learn Random Forest em Modo de script do SageMaker. Também incluímos alguns pré-processamentos de recursos diretamente no pipeline do Scikit-Learn no script de treinamento. Veja o seguinte código:

import numpy as np

def transform_price(X):
    X = X.to_numpy()
    return np.log(
        X[:, 0] / np.nanmin([X[:, 1], X[:, 2]], axis=0),
    ).reshape(-1, 1)

def difference(X):
    X = X.to_numpy()
    return (X[:, 0] - X[:, 1]).reshape(-1, 1)

def fulfillment_difference(X):
    X = X.astype(int)
    return difference(X)

Uma das funções de pré-processamento mais importantes é transform_price, que divide o preço pelo mínimo do preço do concorrente e uma coluna de preço externo. Descobrimos que esse recurso tem um impacto relevante na precisão do modelo. Também aplicamos o logaritmo para permitir que o modelo decida com base nas diferenças de preços relativos, não nas diferenças de preços absolutas.

No training_script.py script, primeiro definimos como construir o Scikit-Learn ColumnTransformer para aplicar os transformadores especificados às colunas de um dataframe:

import argparse
import os
from io import StringIO

import joblib
import numpy as np
import pandas as pd
from custom_transformers import difference
from custom_transformers import fulfillment_difference
from custom_transformers import transform_price
from sklearn.compose import ColumnTransformer
from sklearn.ensemble import RandomForestClassifier
from sklearn.pipeline import Pipeline
from sklearn.preprocessing import FunctionTransformer
from sklearn.preprocessing import OneHotEncoder

def make_preprocessor():
    return ColumnTransformer([
        ('price_by_smallest_cp', FunctionTransformer(transform_price),
         ['price', 'competitor_price', 'external_price']),
        (fulfillment_difference, FunctionTransformer(fulfillment_difference),
         ['fulfillment', 'competitor_'fulfillment']),
        ('feedback_count', 'passthrough',
         ['feedback_count', 'competitor_feedback_count']),
        ('feedback_rating', 'passthrough',
         ['feedback_rating', 'competitor_feedback_rating']),
        (
            'availability_type',
            OneHotEncoder(categories=[['NOW'], ['NOW']],
                          handle_unknown='ignore'),
            ['availability_type', 'competitor_availability_type'],
        ),
        ('min_shipping', FunctionTransformer(difference),
         ['minimum_shipping_hours', 'competitor_min_shipping_hours']),
        ('max_shipping', FunctionTransformer(difference),
         ['maximum_shipping_hours', 'competitor_max_shipping_hours']),
    ], remainder='drop')

No script de treinamento, carregamos os dados do Parquet em um dataframe Pandas, definimos o pipeline do ColumnTranformer e os votos de RandomForestClassifiere treinar o modelo. Em seguida, o modelo é serializado usando joblib:

if __name__ == '__main__':
    parser = argparse.ArgumentParser()
    parser.add_argument('--output-data-dir', type=str,
                        default=os.environ['SM_OUTPUT_DATA_DIR'])
    parser.add_argument('--model-dir', type=str,
                        default=os.environ['SM_MODEL_DIR'])
    parser.add_argument('--train', type=str,
                        default=os.environ['SM_CHANNEL_TRAIN'])

    args = parser.parse_args()

    # load training data
    input_files = [os.path.join(args.train, file)
                   for file in os.listdir(args.train)]
    if len(input_files) == 0:
        raise ValueError
    raw_data = [pd.read_parquet(file) for file in input_files]
    train_data = pd.concat(raw_data)

    # split data set into x and y values
    train_y = train_data.loc[:, 'is_visible']

    if train_y.dtype != 'bool':
        raise ValueError(f'Label 'is_visible' has to be dtype bool but is'
                         f' {train_y.dtype}')

    train_X = train_data.drop('is_visible', axis=1)

    # fit the classifier pipeline and store the fitted model
    clf = Pipeline([
        ('preprocessor', make_preprocessor()),
        ('classifier', RandomForestClassifier(random_state=1)),
    ])
    clf.fit(train_X, train_y)
    joblib.dump(clf, os.path.join(args.model_dir, 'model.joblib'))

No script de treinamento, também temos que implementar funções para inferência:

  • entrada_fn – É responsável por analisar os dados do corpo da solicitação da carga útil
  • modelo_fn – Carrega e retorna o modelo que foi despejado na seção de treinamento do script
  • previsão_fn – Contém nossa implementação para solicitar uma previsão do modelo usando os dados da carga útil
  • previsão_proba – Para desenhar curvas de visibilidade previstas, retornamos a probabilidade de classe usando o predict_proba função, em vez da predição binária do classificador

Veja o seguinte código:

def input_fn(request_body, request_content_type):
    """Parse input data payload"""
    if request_content_type == 'text/csv':
        df = pd.read_csv(StringIO(request_body))
        return df
    else:
        raise ValueError(f'{request_content_type} not supported by script!')


def predict_fn(input_data, model):
    """Predict the visibilities"""
    classes = model.classes_

    if len(classes) != 2:
        raise ValueError('Model has more than 2 classes!')

    # get the index of the winning class
    class_index = np.where(model.classes_ == 1)[0][0]

    output = model.predict_proba(input_data)
    return output[:, class_index]


def model_fn(model_dir):
    """Deserialized and return fitted model

    Note that this should have the same name as the serialized model in the
    main method
    """
    clf = joblib.load(os.path.join(model_dir, 'model.joblib'))
    return clf

A figura a seguir mostra as importâncias do recurso baseado em impureza retornadas pelo Classificador Random Forest.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Com o SageMaker, conseguimos treinar o modelo em uma grande quantidade de dados (até 14 bilhões de transações diárias) sem sobrecarregar nossas instâncias existentes ou ter que configurar uma máquina separada com recursos suficientes. Além disso, como as instâncias são encerradas imediatamente após o trabalho de treinamento, o treinamento com o SageMaker foi extremamente econômico. A implantação do modelo com o SageMaker funcionou sem nenhuma carga de trabalho adicional. Uma única chamada de função no Python SDK é suficiente para hospedar nosso modelo como um endpoint de inferência e pode ser facilmente solicitada de outros serviços usando também o SageMaker Python SDK. Veja o seguinte código:

from sagemaker.sklearn.estimator import SKLearn

FRAMEWORK_VERSION = "0.23-1"
script_path = 'training_script.py'
output_location = f's3://{bucket}/{folder}/output'
source_dir = 'source_dir'

sklearn = SKLearn(
    entry_point=script_path,
    source_dir=source_dir,
    framework_version=FRAMEWORK_VERSION,
    instance_type='ml.m5.large',
    role=role,
    sagemaker_session=sagemaker_session,
    output_path=output_location)

sklearn.fit({'train': training_path})

O artefato do modelo é armazenado no Amazon S3 pela função fit. Como visto no código a seguir, o modelo pode ser carregado como um SKLearnModel objeto usando o artefato do modelo, caminho do script e alguns outros parâmetros. Depois, ele pode ser implantado no tipo de instância e no número de instâncias desejados.

model = sagemaker.sklearn.model.SKLearnModel(
    model_data=f'{output_location}/sagemaker-scikit-learn-2021-02-23-11-13-30-036/output/model.tar.gz',
    source_dir=source_dir,
    entry_point=script_path,
    framework_version=FRAMEWORK_VERSION,
    sagemaker_session=sagemaker_session,
    role=role
)
ENDPOINT_NAME = 'visibility-model-v1'
model.deploy(
    initial_instance_count=1,
    instance_type='ml.m5.large',
    endpoint_name=ENDPOINT_NAME
)

Avalie o modelo em tempo real

Sempre que uma nova notificação é enviada para um de nossos produtos, queremos calcular e enviar o preço ideal. Para calcular os preços ideais, criamos um conjunto de dados de previsão no qual comparamos nossa própria oferta com a oferta de cada concorrente para uma variedade de preços possíveis. Esses pontos de dados são passados ​​para o endpoint do SageMaker, que retorna a probabilidade prevista de ser visível em relação a cada concorrente para cada preço determinado. Chamamos a probabilidade de ser visível de visibilidade prevista. O resultado pode ser visualizado como uma curva para cada concorrente, retratando a relação entre nosso preço e a visibilidade, conforme mostra a figura a seguir.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Neste exemplo, a visibilidade em relação ao Concorrente 1 é quase uma função constante por partes, sugerindo que temos principalmente que diminuir o preço abaixo de um certo limite, aproximadamente o preço do concorrente, para se tornar visível. No entanto, a visibilidade contra o Concorrente 2 não diminui tão acentuadamente. Além disso, ainda temos 50% de chance de sermos visíveis mesmo com um preço muito alto. A análise dos dados de entrada revelou que o concorrente tem uma baixa quantidade de avaliações, que por acaso são muito ruins. Nosso modelo aprendeu que essa plataforma específica de comércio eletrônico prejudica os vendedores com avaliações de feedback ruins. Descobrimos efeitos semelhantes para outros recursos, como canal de atendimento e tempos de envio.

As transformações e inferências de dados necessárias no endpoint do SageMaker são implementadas no AWS Glue. O trabalho do AWS Glue funciona em microlotes nos dados em tempo real ingeridos do Lambda.

Por fim, queremos calcular a curva de visibilidade agregada, que é a visibilidade prevista para cada preço possível. Nossa oferta é visível se for melhor do que as ofertas de todos os outros vendedores. Assumindo independência entre as probabilidades de ser visível contra cada vendedor dado o nosso preço, a probabilidade de ser visível contra todos os vendedores é o produto das respectivas probabilidades. Isso significa que a curva de visibilidade agregada pode ser calculada multiplicando todas as curvas.

As figuras a seguir mostram as visibilidades previstas retornadas do terminal SageMaker.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

A figura a seguir mostra a curva de visibilidade agregada.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Para calcular o preço ideal, a curva de visibilidade é primeiro suavizada e depois multiplicada pela margem. Para calcular a margem, usamos os custos das mercadorias e as taxas. O custo das mercadorias vendidas e as taxas são as informações estáticas do produto sincronizadas por meio do AWS DMS. Com base na função de lucro, o Adspert calcula o preço ideal e o envia para a plataforma de comércio eletrônico por meio da API da plataforma.

Isso é implementado no otimizador de previsão do AWS Lambda.

A figura a seguir mostra a relação entre a visibilidade prevista e o preço.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

A figura a seguir mostra a relação entre preço e lucro.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.

Conclusão

A abordagem existente da Adspert para a maximização do lucro está focada no gerenciamento de lances para aumentar os retornos da publicidade. No entanto, para obter um desempenho superior nos mercados de comércio eletrônico, os vendedores precisam considerar a publicidade e os preços competitivos de seus produtos. Com este novo modelo de ML para prever a visibilidade, podemos estender nossa funcionalidade para ajustar também os preços do cliente.

A nova ferramenta de precificação deve ser capaz de treinamento automatizado do modelo de ML em uma grande quantidade de dados, bem como transformações de dados em tempo real, previsões e otimizações de preços. Neste post, percorremos as principais etapas do nosso mecanismo de otimização de preços e a arquitetura da AWS que implementamos em colaboração com o AWS Data Lab para atingir esses objetivos.

Levar os modelos de ML do conceito à produção geralmente é complexo e demorado. Você precisa gerenciar grandes quantidades de dados para treinar o modelo, escolher o melhor algoritmo para treiná-lo, gerenciar a capacidade de computação durante o treinamento e, em seguida, implantar o modelo em um ambiente de produção. O SageMaker reduziu essa complexidade tornando muito mais simples criar e implantar o modelo de ML. Depois de escolhermos os algoritmos e estruturas corretos da ampla variedade de opções disponíveis, o SageMaker gerenciou toda a infraestrutura subjacente para treinar nosso modelo e implantá-lo em produção.

Se você quiser começar a se familiarizar com o SageMaker, o Workshop Dia de Imersão pode ajudá-lo a obter uma compreensão completa de como criar casos de uso de ML a partir da engenharia de recursos, os vários algoritmos integrados e como treinar, ajustar e implantar o modelo de ML em um cenário semelhante à produção. Ele orienta você a trazer seu próprio modelo e realizar um levantamento e mudança de carga de trabalho de ML no local para a plataforma SageMaker. Ele demonstra ainda conceitos avançados, como depuração de modelo, monitoramento de modelo e AutoML, e ajuda você a avaliar sua carga de trabalho de ML por meio da lente AWS ML Well-Architected.

Se você quiser ajuda para acelerar a implementação de casos de uso que envolvem dados, análises, IA e ML, serverless e modernização de contêineres, entre em contato com o Laboratório de dados da AWS.


Sobre os autores

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.Victor Enrico Jeney é engenheiro sênior de aprendizado de máquina na Adspert com sede em Berlim, Alemanha. Ele cria soluções para problemas de previsão e otimização para aumentar os lucros dos clientes. Viktor tem formação em matemática aplicada e adora trabalhar com dados. Em seu tempo livre, ele gosta de aprender húngaro, praticar artes marciais e tocar violão.

Preço ideal para lucro máximo usando Amazon SageMaker PlatoBlockchain Data Intelligence. Pesquisa Vertical. Ai.Ennio Pastore é arquiteto de dados da equipe do AWS Data Lab. Ele é um entusiasta de tudo relacionado a novas tecnologias que tenham um impacto positivo nos negócios e na vida em geral. Ennio tem mais de 9 anos de experiência em análise de dados. Ele ajuda as empresas a definir e implementar plataformas de dados em todos os setores, como telecomunicações, bancos, jogos, varejo e seguros.

Carimbo de hora:

Mais de Aprendizado de máquina da AWS