Cadene / Cadene/bootstrap.pytorch

Improve logging (logs.json) with SQLite

Open
#23 0 comments 0 reactions 2 assignees Claimed by @MicaelCarvalho View on GitHub
enhancement
Dominant language
Python
Stars
196
Forks
30
PR merge metrics
No merged PRs in 30d

Description

tl;dr: SQLite will replace logs.json

## Our current implementation

We use a [Logger](https://github.com/Cadene/bootstrap.pytorch/blob/master/bootstrap/lib/logger.py) object that stores data as lists of "values" associated to "keys" in a python [dictionary](https://github.com/Cadene/bootstrap.pytorch/blob/master/bootstrap/lib/logger.py#L75). This dictionary is stored in RAM. At the end of a [train epoch](https://github.com/Cadene/bootstrap.pytorch/blob/master/bootstrap/engines/engine.py#L230) or [eval epoch](https://github.com/Cadene/bootstrap.pytorch/blob/master/bootstrap/engines/engine.py#L319), Logger [creates/flushes](https://github.com/Cadene/bootstrap.pytorch/blob/master/bootstrap/lib/logger.py#L233) a `logs.json` file in the experiment directory.

```
logs/myexperiment/logs.json
```

```
{
'train_epoch.epoch': [0, 1, 2, 3, 4, 5],
'train_epoch.acc_top1': [0.0, 5.7, 13.8, 20.4, 28.1, 37.9]
}
```

## Its problems

- If the code crashes before a flush, the data is lost and we want to use Logger to monitor stuff such as CPU memory usage or GPU memory usage before a crash!
- We need to write the full json files each time a new value has been added.
- We need to load the full json files each time a new value has been added to visualize stuff.

## Our constraints

- We want to keep our logs in the experiment directory (no SQL/NoSQL datasets, SQLite maybe?).
- We want to write new values only (For instance, we only write values of epoch 10 at epoch 10).
- We want concurrent reads and writes (at least in differrent keys).

## Some propositions

The following tools store the data on the file system (not in RAM).

### H5PY one file

[see](http://docs.h5py.org/en/stable/)

```
logs/myexperiment/logs.h5py
```

Pros:
- Use numpy
- Easy to access `data['train_epoch.epoch'][10]`

Cons:
- Extendible datasets (when you don't specify the number of size) seems to need "resize" [see](https://stackoverflow.com/questions/16213525/updating-h5py-datasets).
- We encountered a lot of bugs in the past due to HDF5 when we multi-thread/multi-process reading or writing

### LMDB

[see](https://github.com/Cadene/recipe1m.bootstrap.pytorch/blob/master/recipe1m/datasets/recipe1m.py#L79)

```
logs/myexperiment/logs/train_epoch.epoch.lmdb
```

Pros:
-

Cons:
- Cumbersome to use

### netCDF

[see](https://unidata.github.io/netcdf4-python/netCDF4/index.html)

```
logs/myexperiment/logs.nc
```

### One CSV per key / or binary file

```
logs/myexperiment/logs/train_epoch.epoch.csv
```

Pros:
- Very easy to understand, and track

Cons:
- Creates one file per tracked variable
- Associating different variables for the same time step requires reading different files and aligning them
- Difficult to implement (reinvent the wheel)

### SQLite

[see](https://sebastianraschka.com/Articles/2014_sqlite_in_python_tutorial.html)

```
logs/myexperiment/logs.sqlite
```

Pros:
- Can grow big enough
- Allow easy concurrent read/write
- Caching system (TODO source)
- Binary encoding
- Indexing (easy to read only what we want)
- Meta-data: timestamp, epoch_id, iteration_id
- Fault-tolerant (if crash happen)

Cons:
- Requires library to read, user must know SQL to do custom queries/applications (We could add a wrapper over SQLite in Logger)

## Experiments comparison in SQLite

```python
databases = []
for experiment in all_experiments:
databases.append(open...)
for experiment, database in zip(all_experiment, databases):
for metric in list_of_metrics:
min_metric = select... # may be already in cache
max_metric = select... # may be already in cache
(use it here to agglomerate in python)
```

Contributor guide

No contributing guide indexed for this repository

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.