Giliard Godoi

Pesquisador. Aluno de Doutorado. Processamento de Língua Natural. Inteligência Artificial. Aprendizado de Máquina. Análise e Visualização de Dados. Programador Python.

Gerenciando versões de datasets

Tutorial para conhecer o fluxo básico de trabalho com Data Version Control (DVC)

Publicado por Giliard Godoi em Categoria: programming-skills. Tags: dvc

Em um projeto de Data Science é comum termos várias versões de um mesmo conjunto de dados. Podemos retirar instâncias com ruídos, incluir mais instâncias, acrescentar ou diminuir atributos, fazer imputação de valores faltantes. Enfim, são várias as técnicas de pré-processamento e extração de características que podemos aplicar aos nossos dados.

O GitHub possui uma limitação sobre o tamanho de arquivos que podemos subir para os repositórios, e um limite maior pode requerer uma assinatura enterprise ou algo do tipo (Maiores informações aqui). Além disso, subir os nossos dados para o repositório de código não é uma das melhores práticas quando precisamos ter um controle mais rígido sobre o acesso e a disponibilidade dos dados.

Data Version Control (DVC) é uma ferramenta criada para gerenciar versões dos datasets em um projeto de Data Science. O DVC possui um foco no versionamento dos arquivos que contém os nossos dados. Neste tutorial, vamos passar por um passo-a-passo do fluxo básico desse gerenciamento de versões dos conjuntos de dados.

O código para reproduzir alguns passo desse tutorial está disponível no seguinte repositório: dvc-tutorial.

Passo 0: instalar o DVC

A página da documentação traz em detalhes a forma de instalação do DVC. Neste tutorial nós só vamos executar o seguinte comando

$ pip install dvc

Existe também uma extensão do DVC para o VS Code que vale a pena explorar.

Passo #1: Iniciar GIT repositório e o projeto DVC

Digamos que desejamos criar um projeto em um diretório chamado dvc-tutorial. Dentro do diretório, a primeira coisa a se fazer é iniciar um repositório GIT.

O fluxo de trabalho com o DVC está estreitamente relacionado ao do GIT. Um é o melhor amigo do outro. Portanto, o primeiro passo é iniciar um repositório do GIT e logo em seguida iniciar um repositório do DVC.

$ mkdir dvc-tutorial
$ cd dvc-tutorial
$ git init
$ dvc init

Após a inicilização do repositório do DVC vários arquivos de configuração são criados no diretório. São eles uma pasta .dvc e um arquivo .dvcignore. Observe que esses arquivos e diretórios já estão adicionados à área de stage do GIT. Para verificar isso, execute o seguinte comando:

$ git status
Changes to be committed:
  (use "git rm --cached <file>..." to unstage)        new file:   .dvc/.gitignore
        new file:   .dvc/config
        new file:   .dvcignore

O próximo passo é dar um commit para esses arquivos, para que eles sejam monitorados pelo GIT. Assim, caso seja necessário voltar o projeto nesse exato ponto do projeto, os arquivos de configuração do DVC estão disponíveis para recuperarem a exata versão do dataset que estava sendo utilizado naquele momento.

$ git commit -m 'Inicializando projeto DVC'

Outra sugestão é que certamente nós não queremos incluir, mesmo que acidentalmente, o nosso arquivo de dados em um commit do GIT. Para evitar esse tipo de acidente, é interessante adicionar o diretório que contém os nossos arquivos de dados no arquivo .gitignore para eles serem ignorados pelo GIT. Os próximos passos deixarão claro que o que queremos rastrear são arquivos gerados pelo DVC que apontarão para os nossos arquivos de dados.

Passo 2: Rastrear os arquivos de dados

Na documentação oficial, é sugerido obter um dataset de exemplo através do comando dvc get. No nosso caso vamos apenas gerar um dataset fake com o seguinte comando:

$ python fake.py

Ao executarmos o comando dvc status temos a seguinte mensagem:

$ dvc status
There are no data or pipelines tracked in this project yet.
See <https://dvc.org/doc/start> to get started!

Obviamente porque não começamos a rastrear o nosso dataset. Para tanto, basta executar o comando dvc add <caminho-para-dataset>, como no exemplo a seguir:

$ dvc add data/dirty_data.csv
To track the changes with git, run:
    git add 'data\dirty_data.csv.dvc' 'data\.gitignore'To enable auto staging, run:
    dvc config core.autostage true

O DVC gera um arquivo com extensão .dvc no padrão nome-original-do-arquivo.csv.dvc. O exemplo a seguir mostra o conteúdo desse arquivo:

outs:- md5: 416545c6a16b623635d3b35d8a65711b
size: 9757
hash: md5
path: dirty_data.csv

Se gerarmos outro ‘dataset fake’ e adiciona-lo com o dvc add <caminho-para-o-dataset>, será gerado outro arquivo como o anterior.

$ python fake.py # one more time$ dvc add data/dirty_dirty_data.csv

Aqui está um ponto importante!!

É através desses arquivos de hash que o DVC rastreia o arquivo que contém os dados. Se esses arquivos forem perdidos o DVC não tem como saber qual era exatamente o arquivo que estava sendo utilizado.

Toda vez que alterarmos o conteúdo do arquivo do nosso dataset, mesmo que o nome do arquivo seja mantido, o DVC vai saber que não se trata do mesmo dataset através da informação desse hash.

Desta forma é necessário que sempre após gerar uma nova versão do dataset, realizar um commit do arquivo de controle do DVC. Assim, estaremos também versionando os nossos dados.

Porém, como o DVC faz para recuperar o arquivo anterior do nosso conjunto de dados? É isso que vamos ver no próximo passo.

Passo #3: Definir o repositório remoto de dados

O DVC possibilita a configuração de um repositório remoto de dados, que mantém os arquivos correspondentes as várias versões desse dataset. Uma configuração básica é definir um outro diretório na mesma máquina para funcionar como o nosso ”repositório remoto”. Neste exemplo o repositório remoto vai ser apenas um outro diretório no mesmo nível que a pasta do nosso projeto.

$ cd ..
$ mkdir dvc-repo
$ ls dvc-repo # empty folder

Vamos vamos apontar ao repositório remoto com o comando:

$ cd ..
$ cd dvc-tutorial
$ dvc remote add -d myremote ..\dvc-repo

Agora estamos prontos para enviar o nosso dataset para esse repositório de dados remoto:

$ dvc push

Ou obter um dataset com o comando dvc pull.

$ dvc pull

Lembre-se, o DVC sempre vai utilizar aqueles arquivos de hash com a extensão .dvc para buscar o arquivo de dados correspondente. Com o comando dvc pull ele irá buscar o arquivo correspondente ao arquivos hash existentes no repositório do projeto.

A documentação do DVC mostra alternativas para configurações desse repositório remoto utilizando serviços de nuvens de diversos provedores.

Passo #4: Navegar entre as versões dos arquivos

Nesse passo, vamos supor que realizamos alguma alteração no nosso dataset original:

$ python change.py
$ dvc status
data\dirty_data.csv.dvc:    changed outs:
        modified:           data\dirty_data.csv

Caso tenhamos comitados no GIT, podemos nos certificar que o arquivo data/dirty_data.csv.dvc não foi alterado. Isto é, o DVC ainda está apontando a versão anterior do dataset.

Nós podemos realizar um dvc commit para dizer ao DVC que o dataset foi alterado.

$ dvc commit

Novamente, com o comando git status podemos ver que o conteúdo do nosso arquivo data/dirty_data.csv.dvc foi alterado:

$ git status
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)

  modified:   data/dirty_data.csv.dvc

Agora, por um momento, imagine que essa alteração não era exatamente o que queríamos. Podemos voltar o arquivo data/dirty_data.csv.dvc à sua versão anterior. Nesse exemplo, vamos fazer isso com o comando:

$ git restore .\data\dirty_data.csv.dvc

Agora, se executarmos o seguinte comando, o nosso arquivo de dataset volta ao que era antes.

$ dvc checkout
Building workspace index                                                                            |2.00 [00:00,  128entry/s]
Comparing indexes                                                                                   |3.00 [00:00,    ?entry/s]
Applying changes                                                                                    |1.00 [00:00,  64.0file/s]
M       data\dirty_data.csv

O DVC mantém um cache das nossas versões do dataset na pasta .dvc\cache\files\md5\...

E sim, se não tomarmos cuidado, várias versões do dataset pode consumir muito espaço de armazenamento. Porém, talvez apenas precisemos manter os passos seguidos para obter o nosso dataset.

Uma pausa para o café

Antes de prosseguir, vamos fazer uma pausa e recapitular o que aprendemos até aqui. O DVC e o GIT são melhores amigos que devem andar de mãos dadas. Portanto, um fluxo de trabalho possível entre o DVC e o GIT seria.

  1. Inicializar o repositório GIT e o projeto DVC.
  2. Rastrear os arquivos de dados com dvc add
  3. Indicar ao DVC que queremos persistir a versão do dataset com dvc commit
  4. Incluir os arquivos com extensão .dvc para rastreamento do GIT e realizar um commit para persistir as mudanças.

Basicamente esse é um fluxo básico de trabalho com o DVC e o GIT.

5º passo: Incluindo um pipeline

O DVC também permite gerenciar o pipeline de pré-processamento, treinamento e validação de um modelo de Aprendizado de Máquina. Um pipeline é descrito por diferentes estágios necessários para se obter um resultado ou cumprir determinada tarefa.

Através do comando dvc stage add é possível definir um estágio do pipeline. Um estágio é definido através de um nome para identificação e de um comando que define o script que é executado. Também é possível definir os arquivos dos quais o estágio depende (arquivos de dependência) e os arquivos de saída gerados (outputs).

$ dvc stage add --name prepare \
                --deps pipe.py \
                --deps data\dirty_data.csv \
                --outs data\normalized\clean_data.csv \
                python pipe.py
Added stage 'prepare' in 'dvc.yaml'To track the changes with git, run:
        git add dvc.yaml 'data\normalized\.gitignore'

Note que após executar o comando, o texto de saída sugere rastrear o arquivo dvc.yaml com o GIT.

Passo #6: Reproduzir um pipeline

É possível reproduzir todo o pipeline do projeto com o comando dvc repro. O dvc irá executar os scripts de cada estágio, se observar que houve uma mudança nos arquivos que um estágio depende (arquivos de entrada, ou de dados) ou mudanças em parâmetros (registrados no arquivo params.yaml).

$ dvc repro
'data\dirty_data.csv.dvc' didn't change, skippingRunning stage 'prepare':> python .\pipe.pyGenerating lock file 'dvc.lock'Updating lock file 'dvc.lock'To track the changes with git, run:        git add dvc.lock

Ao reproduzir a sequência de estágios de um pipeline, é gerado um arquivo chamado dvc.lock que registra o hash dos arquivos de dependência e arquivos de saída (outputs) gerados. Conforme podemos ver no exemplo de saída reproduzido acima, o DVC recomenda que esse arquivo seja rastreado pelo GIT.

Visualizando o pipeline

É possível visualizar o pipeline, isto é, a sequência de etapas registrada em nosso projeto com o comando dvc dag. É possível gerar essa visualização em diferentes formatos. Para saber mais consulte a documentação nesta página.

$ dvc dag

DAG nesse contexto significa Directed Acyclic Graph. Isso se refere ao fato de que pipelines definidos dentro do dvc não podem possuir dependências circulares, isto é, C depende de B, que depende de A, e este último depende de C.

Também é possível utilizar o comando dvc stage list para listar todos os estágios registrados no arquivo dvc.yaml.

Recapitulando

1) Quais são os arquivos usados pelo DVC para gerenciamento de um projeto? Qual a função de cada um desses arquivos?

Os arquivos são:
- asdfa
- asdfa
- asdfa

Referências