Quel traitement des données dans l’industrie du spatial ?


Retour d’expérience

2020

Nicolas Decoster

@ogadaki

intro

intro

Nicolas Decoster

@ogadaki

1992  -  1999

thèse en traitement d'image

Bordeaux

ingénieur informatique

Nicolas Decoster

@ogadaki

Toulouse

1999  -  2007

informatique et science

Nicolas Decoster

@ogadaki

Toulouse

2007  -  2020

informatique et science

Nicolas Decoster

@ogadaki

Toulouse

2014  -  now

médiation et vulgarisation

Nicolas Decoster

@ogadaki

Toulouse

2020  -  now

démocratisation de la programmation

adacraft.org

R&T détection d’objets

2015

« Évaluation de l’apport de méthodes de détection
d’objets issues du domaine de la photo numérique à
celui de la télédétection »

on se limite à des

algorithmes

d'apprentissage supervisé

notre cas d'étude :

détection d'avions

données d'étude :

12 images Pléiades sur des aéroports

R&T WebAssembly

2018

WebAssembly ?

Web + Assembleur ?

?!?!?

"WebAssembly or wasm is a new portable, size- and load-time-efficient format suitable for compilation to the web."

portable

efficient

compilation to the web

webassembly.org :

fast!

safe!

#include <stdio.h>
int main() {
    printf("WebAssembly\n");
}
$ ls webapp.*
webapp.html  webapp.js  webapp.wasm
$ emcc main.c -o webapp.html

   WebAssembly

$ ls webapp.*
webapp.html  webapp.js  webapp.wasm
$ firefox webapp.html

s'ocuppe du sale boulot à votre place

compilation du C

émission du binaire WebAssembly

création du code JavaScript nécessaire

ajout de dépendances (stdio...)

etc.

liens avec canvas et WebGL

Et sous le capot ?

un format binaire

moteur WebAssembly dédié dans le navigateur

interaction avec le moteur JavaScript

format WebAssembly

(module
  (table 0 anyfunc)
  (memory $0 1)
  (export "memory" (memory $0))
  (export "_Z4facti" (func $_Z4facti))
  (func $_Z4facti (param $0 i32) (result f64)
    (local $1 i64)
    (local $2 i64)
    (block $label$0
      (br_if $label$0
        (i32.lt_s
          (get_local $0)
          (i32.const 1)
        )
      )
      (set_local $1
        (i64.add
          (i64.extend_s/i32
            (get_local $0)
          )
          (i64.const 1)
        )
      )
      (set_local $2
        (i64.const 1)
      )
      (loop $label$1
        (set_local $2
          (i64.mul
            (get_local $2)
            (tee_local $1
              (i64.add
                (get_local $1)
                (i64.const -1)
              )
            )
          )
        )
        (br_if $label$1
          (i64.gt_s
            (get_local $1)
            (i64.const 1)
          )
        )
      )
      (return
        (f64.convert_s/i64
          (get_local $2)
        )
      )
    )
    (f64.const 1)
  )
)
0000000: 6100 6d73 0001 0000 0601 6001 7f01 7c01
0000010: 0203 0001 0404 7001 0000 0305 0001 0701
0000020: 0215 6d06 6d65 726f 0279 0800 5a5f 6634
0000030: 6361 6974 0000 3f0a 3d01 0201 027e 2040
0000040: 4100 4801 000d 0020 42ac 7c01 0121 0142
0000050: 0221 4003 0220 0120 7f42 227c 7e01 0221
0000060: 0120 0142 0d55 0b00 0220 0fb9 440b 0000
0000070: 0000 0000 3ff0 000b
0000000: 0061 736d            # WASM_BINARY_MAGIC
0000004: 0100 0000            # WASM_BINARY_VERSION
# section "Type" (1)
0000008: 01                   # section code
0000009: 00                   # section size (guess)
000000a: 01                   # num types
# type 0
000000b: 60                   # func
000000c: 01                   # num params
000000d: 7f                   # i32
000000e: 01                   # num results
000000f: 7c                   # f64
0000009: 06                   # FIXUP section size
# section "Function" (3)
0000010: 03                   # section code
0000011: 00                   # section size (guess)
0000012: 01                   # num functions
0000013: 00                   # function 0 signature index
0000011: 02                   # FIXUP section size
# section "Table" (4)
0000014: 04                   # section code
0000015: 00                   # section size (guess)
0000016: 01                   # num tables
# table 0
0000017: 70                   # anyfunc
0000018: 00                   # limits: flags
0000019: 00                   # limits: initial
0000015: 04                   # FIXUP section size
# section "Memory" (5)
000001a: 05                   # section code
000001b: 00                   # section size (guess)
000001c: 01                   # num memories
# memory 0
000001d: 00                   # limits: flags
000001e: 01                   # limits: initial
000001b: 03                   # FIXUP section size
# section "Export" (7)
000001f: 07                   # section code
0000020: 00                   # section size (guess)
0000021: 02                   # num exports
0000022: 06                   # string length
0000023: 6d65 6d6f 7279       # export name
0000029: 02                   # export kind
000002a: 00                   # export memory index
000002b: 08                   # string length
000002c: 5f5a 3466 6163 7469  # export name
0000034: 00                   # export kind
0000035: 00                   # export func index
0000020: 15                   # FIXUP section size
# section "Code" (10)
0000036: 0a                   # section code
0000037: 00                   # section size (guess)
0000038: 01                   # num functions
# function body 0
0000039: 00                   # func body size (guess)
000003a: 01                   # local decl count
000003b: 02                   # local type count
000003c: 7e                   # i64
000003d: 02                   # block
000003e: 40                   # void
000003f: 20                   # get_local
0000040: 00                   # local index
0000041: 41                   # i32.const
0000042: 01                   # i32 literal
0000043: 48                   # i32.lt_s
0000044: 0d                   # br_if
0000045: 00                   # break depth
0000046: 20                   # get_local
0000047: 00                   # local index
0000048: ac                   # i64.extend_s/i32
0000049: 42                   # i64.const
000004a: 01                   # i64 literal
000004b: 7c                   # i64.add
000004c: 21                   # set_local
000004d: 01                   # local index
000004e: 42                   # i64.const
000004f: 01                   # i64 literal
0000050: 21                   # set_local
0000051: 02                   # local index
0000052: 03                   # loop
0000053: 40                   # void
0000054: 20                   # get_local
0000055: 02                   # local index
0000056: 20                   # get_local
0000057: 01                   # local index
0000058: 42                   # i64.const
0000059: 7f                   # i64 literal
000005a: 7c                   # i64.add
000005b: 22                   # tee_local
000005c: 01                   # local index
000005d: 7e                   # i64.mul
000005e: 21                   # set_local
000005f: 02                   # local index
0000060: 20                   # get_local
0000061: 01                   # local index
0000062: 42                   # i64.const
0000063: 01                   # i64 literal
0000064: 55                   # i64.gt_s
0000065: 0d                   # br_if
0000066: 00                   # break depth
0000067: 0b                   # end
0000068: 20                   # get_local
0000069: 02                   # local index
000006a: b9                   # f64.convert_s/i64
000006b: 0f                   # return
000006c: 0b                   # end
000006d: 44                   # f64.const
000006e: 0000 0000 0000 f03f  # f64 literal
0000076: 0b                   # end
0000039: 3d                   # FIXUP func body size
0000037: 3f                   # FIXUP section size

format binaire

format texte

(s-expression)

format binaire avec commentaires

moteur WebAssembly

module

instance

imports et exports

mémoire linéaire

format binaire

Notions

$ wget http://zlib.net/zlib-1.2.11.tar.gz
$ tar xf zlib-1.2.11.tar.gz
$ cd zlib-1.2.11.tar.gz
$ emconfigure ./configure --prefix=./dist
$ emmake make
$ emmake make install

Emscripten pour compiler des outils existants

WebAssembly, pour faire quoi ?

jeux

édition de vidéo ou d'image

application musicale

reconnaissance d'image

VR et AR

visualisation et simulation scientifique

etc.

je prends

je prends

Exemples concrets

d'utilisation de WebAssembly

use case

Magellium - CNES

un outil de visualisation d'images satellite

avec traitements

100% côté navigateur

dans ces outils j'ai manipulé

 

des "petites images" (moins de 100 Mo)

 

dans des formats standards (PNG...)

lisibles par les navigateurs

en général

les données satellites

sont dans d'autres formats

JPEG 2000

très utilisé pour les images satellites

 

images de très grande taille

 

format de compression multiéchelle

 

encodages exotiques

(plus que trois "couleurs", pas de 8bits)

 

 

 

source : wikipedia

$ ll IMG_R2C1.JP2
-rw-r--r-- 1 ada ada 3.3G Nov 12  2009 IMG_R2C1.JP2
$ gdalinfo IMG_R2C1.JP2
  Driver: JP2OpenJPEG/JPEG-2000 driver based on OpenJPEG library
  Files: IMG_R2C1.JP2
  Size is 57344, 28672
  Band 1 Block=4096x4096 Type=UInt16, ColorInterp=Red
    Overviews: 28672x14336, 14336x7168, 7168x3584, 3584x1792, 1792x896
    NBITS=12
  Band 2 Block=4096x4096 Type=UInt16, ColorInterp=Green
    Overviews: 28672x14336, 14336x7168, 7168x3584, 3584x1792, 1792x896
    NBITS=12
  Band 3 Block=4096x4096 Type=UInt16, ColorInterp=Blue
    Overviews: 28672x14336, 14336x7168, 7168x3584, 3584x1792, 1792x896
    NBITS=12
  Band 4 Block=4096x4096 Type=UInt16, ColorInterp=Undefined
    Overviews: 28672x14336, 14336x7168, 7168x3584, 3584x1792, 1792x896
    NBITS=12

mais JPEG 2000 n'est pas un format lisible par les navigateurs

il existe des bibliothèques de lecture en C

OpenJPEG

open source

Kakadu

payant (licence de développement)

la référence pour le JPEG 2000

on utilise emscripten pour compiler Kakadu en WebAssembly

$ kdu_expand \
      -i full_image.jp2 \
      -o extract.bmp \
      -region {0.3,0.05},{0.8,0.02}

Ligne de commande pour

extraire une partie d'une image JPEG 2000 et pour l'enregistrer en BMP

affichage dans le navigateur ?

bibliothèque JavaScript

affichage de

données cartographiques

et d'images

map.addLayer(new ol.layer.Tile({
    source: new ol.source.TileImage({
        tileLoadFunction: function (tile, zxyTileUrl) {
            const [ x, y, w, h, reduce ] = getKduRegion(zxyTileUrl)
            callWasmKduExpand([
                '-i', inputJp2File,
                '-o', subBmpFile,
                '-region', `{${x},${y}},{${w},${h}})`,
                '-reduce', `${reduce}`
            ])
            const binary = readFileFromEmscriptenFS(subBmpFile)
            const base64String = binaryArrayToBase64String(binary)
            const dataUrl = 'data:image/bmp;base64,' + base64String
            tile.getImage().src = dataUrl
        }
    })
}))

ol = OpenLayers

affichage ok et fluide !

(démo dans quelques slides)

mais...

uniquement sur des petites images JP2

(max 100 Mo)

raison :

fichiers stockés dans la mémoire du navigateur

(MEMFS d'emscripten)

comment lire et afficher

des images de plusieurs Go ?

utiliser l'API File de JavaScript

permet d'accéder à un intervalle d'octets si appelé depuis un Web Worker !

emscripten fournit

le pseudo système de fichiers WORKERFS

qui permet cela

wasm

archi pour fichier local

affichage d'un fichier local de

plusieurs Go

ok et fluide !

affichage d'un fichier distant de

plusieurs Go ?

archi pour fichier local

archi pour fichier distant

wasm

wasm

affichage d'un fichier distant de

plusieurs Go

ok et fluide !

WebAssembly

en dehors du navigateur

#include <stdio.h>
int main() {
    printf("WebAssembly\n");
}
$ emcc main.c -o cli.js
$ ls
cli.js  cli.wasm  main.c
$ node cli.js
WebAssembly

détection d'avions avec l'algorithme ICF

traitements en batch de la

détection d'avions avec ICF

sur un ensemble de grandes images

avec le même binaire WebAssembly

mais côté serveur

Google Cloud

Functions

Google Cloud

PubSUb

old

High Resolution

Snow & Ice

Monitoring

Production de cartes

de glace et de neige

sur l'Europe

en "temps réel"

image Sentinel 2

temps réel ?

3 h

entre

image Sentinel 2

disponible (ESA)

cartes de neige et de glace

calculées

2019 - now

EEA

EEA

ESA

Union européenne

Copernicus permet de rassembler l'ensemble des données obtenues à partir de satellites environnementaux et d'instruments de mesure sur site, afin de produire une vue globale et complète de l'état de notre planète

~ 700 images par jour

arrivée progressive

entre 15h et 22h

mais pas toujours...

temps nécessaire

pour calculer

les cartes de neige et de glace

sur une image

~40 min

un job

Orchestrator
main process controlling the system

Administration
System monitoring and maintenance

Worker pool
run multiple Snow and Ice softwares

Database
job descriptions

Storage
standard S3 object storage

 

Data Access
S&I products for the end-users

 

worker VM configuration:

2 vCores                   16 GB   RAM               64 GB local SSD

jusqu'à 200 VM en même temps

hébergeur cloud utilisé

technologie de cet hébergeur

$ openstack flavor list

+-----+-----------+-------+------+-----------+-------+-----------+
| ID  | Name      |   RAM | Disk | Ephemeral | VCPUs | Is_Public |
+-----+-----------+-------+------+-----------+-------+-----------+
| 1   | m1.tiny   |   512 |    1 |         0 |     1 | True      |
| 2   | m1.small  |  2048 |   20 |         0 |     1 | True      |
| 3   | m1.medium |  4096 |   40 |         0 |     2 | True      |
| 4   | m1.large  |  8192 |   80 |         0 |     4 | True      |
| 5   | m1.xlarge | 16384 |  160 |         0 |     8 | True      |
+-----+-----------+-------+------+-----------+-------+-----------+
$ openstack \
    server create \
    --flavor 1 \
    --image 397e713c-b95b-4186-ad46-6126863ea0a9 \
    --security-group default \
    --key-name KeyPair01 \
    --user-data cloudinit.file \
    my_new_server

+--------------------------------------+-----------------------------------------------+
| Field                                | Value                                         |
+--------------------------------------+-----------------------------------------------+
...
| accessIPv4                           |                                               |
| adminPass                            | E4Ksozt4Efi8                                  |
| created                              | 2016-11-30T14:48:05Z                          |
| flavor                               | m1.tiny                                       |
| id                                   | 89015cc9-bdf1-458a-8518-fdca2b4a5785          |
| image                                | cirros (397e713c-b95b-4186-ad46-6126863ea0a9) |
| key_name                             | KeyPair01                                     |
| name                                 | my_new_server                                 |
| project_id                           | 5669caad86a04256994cdf755df4d3c1              |
| properties                           |                                               |
| security_groups                      | [{u'name': u'default'}]                       |
| status                               | BUILD                                         |
| updated                              | 2016-11-30T14:48:05Z                          |
| user_id                              | c36cec73b0e44876a4478b1e6cd749bb              |
+--------------------------------------+-----------------------------------------------+
resource "openstack_compute_instance_v2" "basic" {
  name            = "basic"
  image_id        = "397e713c-b95b-4186-ad46-6126863ea0a9"
  flavor_id       = "1"
  key_pair        = "KeyPair01"
  security_groups = ["default"]

  network {
    name = "my_network"
  }
}

Terraform

création d'une VM sur OpenStack

l'infrastructure du projet

est gérée avec Terraform

ça facilite les modifications

et les redéploiements

l'infrastructure est décrite avec du code

elle est versionnée comme tout autre code

le système comprend

un ensemble de services

création d'un job, sa configuration, son lancement, etc.

chaque service est un composant logiciel packagé dans un container Docker

comment s'assurer que les services sont bien en train de tourner sur une VM ?

Problématique :

Solution :

Nomad

bonus

Nomad est également utilisé

pour gérer les queues de jobs

de calcul des cartes

de neige et de glace

nomad server

VM nomad

nomad client

VM orchestrator

nomad client

VM worker 1

service job-config

service job-results

run job 64A8B

nomad client

VM worker 2

run job 197C0

etc.

service job-creation

service ...

Merci !

Nicolas Decoster      @ogadaki

Informatique et données satellites

By Nicolas Decoster

Informatique et données satellites

Quel traitement des données dans l’industrie du spatial ? Retour d’expérience - novembre 2020 - Université Fédérale Toulouse Midi-Pyrénées

  • 259