venerdì 31 gennaio 2020

Tensorflow Lite su Arduino Ble 33

A questo link e' comparso un interessante esempio su come utilizzare i sensori (accelerometro e giroscopio) di una Arduino BLE per addestrare una rete neurale con Tensorflow Lite e poi utilizzare la stessa libreria per classificare le gesture sempre tramite  Arduino



Per prova ho inserito la Arduino sotto ad un guanto (per tenerla bloccata) e poi registrando un centinaio di rotazione del polso verso l'interno e verso l'esterno


L'ultima modifica che ho apportato e' di modificare a 50 il numero di campioni per gesture
Una volta salvata due file csv (uno per movimento) ho utilizzato questo Colab per creare il file model. h


Grafico accelerazione di riferimento
Come si deve dai grafici l'errore del modello in train/validation e' estremamente ridotto

Grafico giroscopi di riferimento

Training and validation loss


Stesso grafico precedente eliminando i primi 100 dati


Risultati validazione

Il risultato del Notebook sono un file di modello di Tensorflow Lite ed un file model.h che deve essere copiato nello sketch ImuClassifier per fare il deploy del modello

Devo ammettere che il sistema funziona ma e' lontano dall'essere perfetto. Devo ancora capire se e' un problema di posizionamento del sensore durante le varie proprie (che per ovvi motivi non e' sempre identico) od un addestramento errato




SSTV da ISS 30/01/2020 17:33 GTM Firenze

Dopo aver avuto un contatto radio con la ISS via voce nel transito del 30 gennaio 2020 alle 17:33 GMT sono riuscito a registrare una trasmissione della ARISS SSTV


La ricezione e' avvenuta da Firenze con un normalissimo scanner radio palmare Icom IC-R5 ed antenna standard registrando l'audio direttamente dal cellulare


Per la cronaca avevo acceso anche un Baofeng UV-5R ma con questo dispositivo il segnala era praticamente sommerso dal rumore nonostante le due radio fossero  a meno di 3 metri di distanza.


La decodifica e' stata effettuata con la applicazione Android Robot360




L'immagine e' stata poi postata al sito  https://www.spaceflightsoftware.com/ARISS_SSTV/

Alla fine ho anche mandato ad Ariss SSTV Archive la mia immagine ed e' stato impressionante vedere il numero di radioamatori che hanno condiviso nello stesso momento le immagini a giro per il mondo


mercoledì 29 gennaio 2020

NOAA 18

Una volta capito come funziona ci si prende gusto. A questo giro ho provato a ricevere i dati dal satellite NOOA18, un satellite meteo in orbita polare

Il passaggio sull'Europa e' avvenuto alle 21:15 (GMT+1) del 28 gennaio (fonte https://www.heavens-above.com/)






La caratteristica di questo satellite e' che trasmette sui 137.912 MHz con una ampiezza di banda di 38 KHz. In WebSDR per allargare l'ampiezza di banda si deve selezionare FM e poi con il mouse selezionare ciascun estremo della banda e trascinarlo fino a quando non viene coperta tutta l'estenzione del segnale. Il segnale e' caratterizzato da una serie di righe parallele nella modalita' waterfall

Waterfall


Spettro

Vista la frequenza di esercizio non potevo usare il WebSdr utilizzato per la  ISS e mi sono spostato su questo link http://erc-websdr.esa.int/

Di fatto il problema principale con NOOA e' possedere una antenna a polarizzazione circolare destra

Il file .wav deve essere processato attraverso il software WxtoImg ma e' posssibile utilizzare anche https://noaa-apt.mbernardi.com.ar/

Se si usa WxtoImg si deve prima prendere il file .wav in uscita da WebSDR e processarlo con Audacity per ricampionarlo da 8000 Hz s 11025 Hz. Si salva il file ma cio' comporta che il nuovo file abbia un timestamp diverso dal file iniziale. Per correggere questo problema si utilizza il comando

touch -a -m -t 202001282130.00 t1.wav
dove il timestamp e' formato YYYYMMDDHHMM.SS

Il software si chiama in questo modo perche' il protocollo di trasmissione e' denominato WeFax ed e' in pratica molto simile al buon vecchio sistema Fax che si usava in ufficio
Il servizio APT e' invece una trasmissione di due immagini relative a due bande (in questo caso nel termico) di 2080 x 909 pixels

Elaborazioni con WxToImg
Temperatura Mare


MCIR


Tenpeartura


se si usa noaa-apt i passi di cambio ora e resampling sono eseguiti in automatico e questo e' il risultato. Di fatto con questo software non possono essere eseguite elaborazioni. Le due bande vengono visualizzate a fianco con inclusa la banda di sincronia del segnale 



Per confronto questa e' la stessa immagine acquisita da https://www.osservatoriometeoesismicoperugia.it/satellitipolari/index.html


La differenza principale e' che qui le nuvole sono bianche mentre in wxtoimg risultano grigie

martedì 28 gennaio 2020

ISS Ham Radio Luca Parmitano 27/01/2020 17:38 GMT

Erano anni che provavo ad ascoltare il canale amatoriale della Stazione Spaziale ISS sulla frequenza 145.800 MHz con radio sempre migliori (ma sempre a basso costo da scanner palmari a RTL-SDR)

Ma di fatto bisogna avere fortuna perche' i transiti della ISS sono di pochi minuti e di solito gli astronauti sono impegnati in altre cose (si tratta di una Ham Radio, non si tratta della radio effettiva di lavoro con il controllo missione)



Finalmente ci sono riuscito anche se non usando la mia apparecchiatura.
Visto che il transito sull'Europa era previsto quando non ero in casa mi sono collegato con il sito http://farnham-sdr.com/ dove si puo' usare una radio RTL-SDR a piacimento (l'antenna si trova nella parte meridionale dell'Inghilterra)

Tramite https://www.heavens-above.com/ era calcolato un transito alle 16:38 GMT (in Italia 17:38) e puntualmente come la ISS e' emersa dall'orizzonte ho visto il segnale sul waterfall




La cosa che mi ha fatto ancora piu' piacere e' stato trovare Luca Parmitano in trasmissione (avevo provato ad ascoltare anche nella precedente missione 36 senza nessun successo)

La cosa impressionante e' lo spostamente doppler del segnale. La frequenza di riferimento e' di 145.800 MHz ma quando emerge dall'orizzonte la frequenza e' oltre 145.803 MHz


per poi spostarsi rapidamente verso sinistra nello spettro, Nel momento di passaggio allo zenit lo spostamento Doppler e' cosi' rapido che la linea di riferimento sullo spettro e' chiaramente inclinata (la ISS e' dannatamente veloce!). Quando e' scomparsa all'orizzonte opposto la frequenza era vicino a 145.796 MHz




lunedì 27 gennaio 2020

Mobike e BLE

Mentre stavo giocherellando con lo scanner Bluetooth LE mi e' apparso in lista un dispositivo Mobike ed ho visto che era stata appena parcheggiata una bicicletta a noleggio fuori dall'ufficio. Avevo sempre pensato che le Mobike fossero basate tutte su comunicazioni dati su rete cellulare ma a quanto sembra non e' proprio cosi..di fatto vengono esposte due servizi di uno scrivibile via BLE




c'e ovviamente chi ha fatto un'analisi decisamente piu' apprfondita

https://gsec.hitb.org/materials/sg2018/D2%20-%20Hacking%20BLE%20Bicycle%20Locks%20for%20Fun%20and%20(a%20Small)%20Profit%20-%20Vincent%20Tan.pdf

e c'e' anche chi ha smontato un lucchetto Mobike trovandoci dentro un modulo telefonico, un GPS ed un processore STM32

https://projectgus.com/2017/04/sharing-bikes-in-shanghai/

In ogni caso la gran parte del lavoro di scambio dati per lo sblocco e' svolto dal telefono del cliente
Sarei curioso di sapere come e' stato risolto da Mobike il problema di alimentare un sistema cosi' energivoro (GPS+Cellulare possono drenare in modo molto veloce le batterie)

BLE Write Characteristic da Android

Dopo il precedente tentativo di leggere una caratteristica BLE da Python adesso un tentativo di scrivere una caratteristica (lo so e' una brutta traduzione) da Android su un dispositivo BLE

Lo sketch Arduino e' stato modificato per esporre una caratteristica 2A30 in modalita' lettura/scrittura, settare il valore a 3, leggere il valore e se e' differente da 3 spengere il Led di Arduino

=================================================================
#include <ArduinoBLE.h>

BLEService numero("180F");
BLEUnsignedCharCharacteristic casuale("2A19",BLERead | BLENotify); 
BLEUnsignedCharCharacteristic scrittura("2A30",BLERead | BLEWrite); 


long previousMillis = 0;  
byte test =3 ;

void setup() {
  Serial.begin(9600);  
  while (!Serial);
  pinMode(LED_BUILTIN, OUTPUT); 
  if (!BLE.begin()) {
    while (1);
  }

  BLE.setLocalName("Random");
  BLE.setAdvertisedService(numero); 
  numero.addCharacteristic(casuale);
  numero.addCharacteristic(scrittura);
  
  BLE.addService(numero); 
  casuale.writeValue(0); // set initial value for this characteristic
  scrittura.writeValue(2);
  BLE.advertise();
}

void loop() {
  int i = 0;
  BLEDevice central = BLE.central();
  if (central) {
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 20) {
        previousMillis = currentMillis;
        scrittura.readValue(test);
        if(test ==3)
            {
            Serial.println(test);
            digitalWrite(LED_BUILTIN, HIGH);
            }
            else
            {
            Serial.println(test);
            digitalWrite(LED_BUILTIN, LOW);
            }
            
      }
    }
    digitalWrite(LED_BUILTIN, LOW);    
  }
}

=================================================================

Per Android ho usato la libreria a questo indirizzo . Ne esistono di piu' complete ma
in questo caso avevo bisogno di semplicita'
=================================================================
package com.ble.ellamma.ble;
import android.bluetooth.BluetoothDevice;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.util.Log;
import com.ble.ellamma.bleand.Ble;
import java.util.UUID;

public class MainActivity extends AppCompatActivity {

    private static final String MAC_ADDRESS = "ED:CB:86:2A:68:C1";    private static final UUID BLE_NOTIFY_CHARACTER =  UUID.fromString("00002a19-0000-1000-8000-00805f9b34fb");    //.00002a19-0000-1000-8000-00805f9b34fb--18
    private static final UUID BLE_SERVICE = UUID.fromString("0000180f-0000-1000-8000-00805f9b34fb");
    private static final UUID CLIENT_CCD =  UUID.fromString("00002a30-0000-1000-8000-00805f9b34fb");

    ArrayList<String> getDevicess;    List<BluetoothDevice> getConnectedDevicess;


    @Override    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);        
        setContentView(R.layout.activity_main);
        getDevicess = new ArrayList<>();        
        getConnectedDevicess = new ArrayList<>();
        Ble ble = new Ble(this,getApplicationContext(),".Myreceiver");
        ble.enableBle();        
        //ble.scanLeDevice(true,1000);        
        //ble.getDevices();

        ble.connectBLE(MAC_ADDRESS);        
        byte dati[] = "A".getBytes();        
        ble.writeCharacteristics(dati,BLE_SERVIVE,CLIENT_CCD,true);        
        ble.disConnectBLE();
    }

    public void onReceive(Context context, Intent intent) {
        //String data = intent.getStringExtra("data");        
        //Log.w("Luca", "Request Recieved On MyReciever ::" + data);
    }

}





venerdì 24 gennaio 2020

Lenovo Ultrabay HD e LVM

Dato che avevo uno slot libero sul mio Lenovo T430 mi sono comprato una estensione SATA per lo slot Ultrabay. Ho riutilizzato un disco SSD che ho preso da un'altra macchina ma al momento di montarlo sulla Debian Box non riuscivo a vederlo


Guardando con GParted il disco era formattato LVM. A questo punto ho scaricato il pacchetto LVM

apt-get install lvm2

con vgscan ho scansionato i dischi ed ho attivato il volume con

vgachange -ay centos

con lvs si possono vedere le partizioni sul disco. A questo punto si puo' montare il filesystem

mount /dev/centos/home /media/ -o ro,user

a questo punto per fare le cose per bene sarebbe da inserire in fstab. Per avere lo UUID si puo' digitare blkid

giovedì 23 gennaio 2020

Cython

Era un po' di tempo che volevo provare Cython, la versione compilata di Python, ma non avevo mai avuto la necessita'. Con il trasferimento dati via BLE del precedente post pensavo che il collo di bottiglia fosse legato a Python e non al transfer rate di BLE ed ho cosi' convertito lo script in Python tramite Cython. In pratica il primo passo e' la conversione in C mentre il secondo passo e' una classica compilazione con GCC per avere un eseguibile


cython --embed -o ble_test.c ../ble_test.py
gcc -Os -I /usr/include/python2.7/ -o ble_test ble_test.c -lpython2.7 -lpthread -lm -util -ldl


...e no, il problema non era Python

BLE Arduino Nano 33

Un eesmpio di scambio dati via Bluetooth LE tra una scheda Arduino Nano 33 BLE ed un PC



La Arduino Nano BLE 33 e' una scheda interessante perche' oltre al Bluetooth LE sono disponibili una IMU (LMS9DS1), un microfono digitale (MP34DT05), un sensore di colore e prossimita' (APDS9960), un sensore di pressione atmosferica (LPS22HB), un sensore di umidita' relativa e temperatura (HTS221)

Lo sketch su Arduino apre un servizio su BLE con numero 180F ed una caratteristica 2A19 in cui vengono salvati i dati di un contatore progressivo da 0 a 255 (questo per fare in modo che sul lato PC si sia in grado di vedere se si perdono pacchetti)

Lato Arduino
================================================
#include <ArduinoBLE.h>

BLEService numero("180F");
BLEUnsignedCharCharacteristic casuale("2A19",BLERead | BLENotify); 

long previousMillis = 0;  

void setup() {
  Serial.begin(9600);  
  while (!Serial);
  pinMode(LED_BUILTIN, OUTPUT); 
  if (!BLE.begin()) {
    while (1);
  }

  BLE.setLocalName("Random");
  BLE.setAdvertisedService(numero); 
  numero.addCharacteristic(casuale); 
  BLE.addService(numero); 
  casuale.writeValue(0); // set initial value for this characteristic
  BLE.advertise();
}

void loop() {
  int i = 0;
  BLEDevice central = BLE.central();
  if (central) {
    digitalWrite(LED_BUILTIN, HIGH);
    while (central.connected()) {
      long currentMillis = millis();
      if (currentMillis - previousMillis >= 20) {
        i++;
        casuale.writeValue(i%255);
        previousMillis = currentMillis;
      }
    }
    digitalWrite(LED_BUILTIN, LOW);    
  }
}
================================================

Per verificare che i dati vengano inviati correttamente si puo' usare gattool

================================================
gatttool -b ED:CB:86:2A:68:C1 -I
[ED:CB:86:2A:68:C1][LE]> connect
Attempting to connect to ED:CB:86:2A:68:C1
Connection successful
[ED:CB:86:2A:68:C1][LE]> char-read-uuid 2A19
handle: 0x000b value: 41
================================================

A questo punto con la libreria Bluepy si possono leggere i dati inviati dalla Arduino

================================================
from bluepy import btle
from bluepy.btle import UUID, Peripheral

addr = "ED:CB:86:2A:68:C1"
conn = Peripheral(addr, "public")

print ("-Servizi")
services = conn.getServices()
for service in services:
print(service.uuid)


print("-Caratteristica")
charac_dic = service.getCharacteristics()
for charac in charac_dic:
print(charac.uuid)
if charac.uuid == "2a19":
print ("Trovata")
Data_char = charac
print(Data_char)
Data_handle = Data_char.getHandle()
print Data_handle
while True:
print (ord(charac.read()))
================================================

la trasmissione dati in questo modo e' piuttosto lenta..circa un dato ogni decimo di secondo.
Usando la tecnica di subscribe and notify la Arduino invia i dati al PC senza la necessita' per quest'ultimo di richiederli. Con questa tecnica non si perde nessun pacchetto

================================================
from bluepy import btle
from bluepy.btle import UUID, Peripheral
import struct

def listAll(p):
for svc in p.getServices():
print(svc.uuid.getCommonName())
for ch in svc.getCharacteristics():
print(" " + str(ch.valHandle) + ": " + ch.uuid.getCommonName())

class MyDelegate(btle.DefaultDelegate):
    def __init__(self):
        btle.DefaultDelegate.__init__(self)

    def handleNotification(self, cHandle, data):
print(ord(data))

addr = "ED:CB:86:2A:68:C1"
p = btle.Peripheral(addr,"public")
services=p.getServices()
for service in services:
   print(service.uuid)

p.setDelegate( MyDelegate() )

listAll(p)

svc = p.getServiceByUUID("0000180f-0000-1000-8000-00805f9b34fb")
ch = svc.getCharacteristics()[0]
p.writeCharacteristic(ch.valHandle+1, b'\x01\x00', withResponse=True)

while True:
    if p.waitForNotifications(1.0):
        continue
    print "Waiting..."

martedì 21 gennaio 2020

Debian Bullseye e Xrandr

Mettendo a posto una Debian Testing BullsEye su un Lenovo Thinkpad serie T volevo usare il trucco di newrez per aumentare la risoluzione dello schermo ma nonostante tutto xrandr sembrava non funzionare

Ho scoperto dopo un po' che era in uso Wayland e cio' impediva l'uso di xrandr. A questo punto e' stato necessario editare il file /etc/gdm3/daemon.conf e decommentare WaylandEnable=false

Al successivo riavvio e' stato possibile far funzionare newrew semplicemente modificando LVDS1 a LDVS-1 e VGA1 a VGA-1

sabato 18 gennaio 2020

Copiare docker container su diverse macchine

Per spostare un container tra due macchine si procede prima creando un file .tar con docker save

docker save -o /home/luca/container.tar DOCKER_ID



per avere un tgz si puo' usare

docker save DOCKER_ID | gzip -c > container.tar.gz

una volta copiato il file sulla seconda macchina il container puo' essere installato con

docker load -i container.tar

facendo cosi' si avranno Repository e Tag impostati a <none>. Per completare il lavoro si usa

docker image tag DOCKER_ID nome_repository nome_tag 

con DOCKER_ID recuperato tramite il comando docker image ls e impostando il nome_repository con la sintassi per esempio tensorflow/tensorflow mentre il nome_tag puo' essere per esempio latest

giovedì 16 gennaio 2020

Single Step LSTM Time Series Tensorflow

Le serie tempo sono successioni di uno (univariata) o piu' parametri (multivariata) acquisiti da strumenti a cadenza regolari di tempo (il tempo definisce l'indice della serie)

A differenza di una serie normale di dati qui l'ordine assume una importanza perche' ciascun dato e' collegato a quello immediatamente successivo e antecedente in una successione che i matematici direbbero continua

Un metodo per poter prevedere il prossimo dato nella successione usando le reti neurali e' quello di usare l'approccio LSTM (Long Short Term Memory) riconducibili alle reti RNN

Il fato che il titolo indichi Single Step vuol dire che l'algoritmo e' in grado di individuare solo il valore della variabile al tempo T+1 e non e' possibile avere piu' dati previsti

Un sistema comodo per esplorare l'algoritmo e' quello di usare il codice a questo GitHub
Nel file di configurazione training_config.json si possono impostare le caratteristiche della rete neurale come i dati di train e test, il dropout ma soprattutto si imposa la window_size ovvero la grandezza della finestra che viene usata dall'algoritmo per calcolare il valore al tempo T+1

Per effettuare ho preso i dati della stazione meteo di Antella (localita' vicino a Firenze) nel periodo dicembre 2002 aprile 2010 con misure giornaliere della temperatura massima


i dati sono stati processati mediante il codice linkato in precedenza

Il risultato della validazione dei dati risulta sostanzialemente corretta

Nel grafico sottostante (ripreso da qui) si osservano tutti i limiti del metodo nel caso di estrapolazione di piu' di un valore sul tren futuro. Usando una finestra mobile e' stato simulata la previsione di trend nel futuro su varie porzioni dei dati e si vede abbastanza chiaramente che la predizione, essendo legata alla finestra dei dati immediatamente precedenti, puo; indurre anche errori grossolani


asdasd

mercoledì 15 gennaio 2020

Jupyter notebook inside docker

Per poter utilizzare un Notebook Jupyter contenuto all'interno di un container docker si avvia prima il container con una sintassi del tipo


docker run -it --rm -p8888:8888 -v /home/luca/Downloads/time-series-forecasting-rnn-tensorflow-master:/tmp2 -w /tmp2  intelaipg/intel-optimized-tensorflow:2.0.0-mkl-py3

montando la directory esterna al docker dove sono contenuti i notebook

a questo punto dall'interno del container si lancia

jupyter notebook --ip 0.0.0.0 --no-browser --allow-root


Docker tensorflow ottimizzato per Intel

Usando la versione standard di Tensorflow distribuita da Google si nota il messaggio "Your CPU supports instructions that this Tensorflow binary was not compiled to use: AVX2 FMA"

Questo perche' la versione distribuita e' compilata per funzionare su un ampio spettro di calcolatori

La soluzione per avere una versione ottimizzata per tutte le istruzioni della CPU e' quella di compilare da sorgenti Tensorflow oppure di utilizzare dei container docker che gia' hanno il codice compilato ottimizzato. In questo senso vengono utili i container prodotti da Intel con il supporto MKL (Math Kernel for Deep Neural Network)

Vi sono versioni con Python 2.7
docker run -it -p 8888:8888 intelaipg/intel-optimized-tensorflow

e Python 3.6
docker run -it -p 8888:8888 intelaipg/intel-optimized-tensorflow:2.0.0-mkl-py3




Per modificare in modo permanente il container con le librerie di normale uso si lancia

docker run -it intelaipg/intel-optimized-tensorflow:2.0.0-mkl-py3 /bin/bash 

e con pip si installano normalmente le librerie Python (per esempio Pandas, Matplotlib...)
al termine si fa exit e con 

docker ps -a 

si copia l'ID del container modificato. A questo punto con commit si modifica in modo definitivo il container

docker commit Docker_ID intelaipg/intel-optimized-tensorflow:2.0.0-mkl-py3





lunedì 13 gennaio 2020

Videoscrittura o computer

Frugando tra dei libri destinati al cestino ho trovato questo libro del 1984 "Scrivere con il computer" in cui l'autore ci guida alla domanda se sia meglio un sistema di video scrittura, come la serie Olivetti ETV,  oppure un PC con Wordstar


Fa strano pensarlo ai giorni nostri ma ricordo che ai tempi del liceo (tipo 1987-1988) il professore di filosofia aveva acquistato un sistema di video scrittura mentre il professore di italiano usava un Olivetti M15 

giovedì 9 gennaio 2020

Foraminiferi Tensorflow : train vs retrain model con Tensorflow

Continua la mia battaglia personale con le reti neurali per il riconoscimento di foraminiferi.
Attualmente le strade percorse sono state due: la prima prevede di scrivere ed addestrare da zero una rete neurale CNN mentre la seconda prevede il retraining di reti gia' addestrate (nello specifico mobilenet v2 ed inception v3)

Quali sono i risultati migliori??
In entrambi i casi le corrette previsioni del modello si e' aggirato intorno al 60 % (quindi poco performante ma l'oggetto di studio e' di per se difficile anche per un umano)

Retrain Inception v3
La reale differenze e' che il modello con retrain ha la tendenza di indovinare o sbagliare completamente le previsioni mentre con la rete addestrata da zero la distribuzione di successi /insuccessi e' molto piu' distribuita

CNN Trained

Predizione classificazione immagini con Tensorflow da modelli .h5

In un esempio precedente avevo usato il modello .tflite per fare predizione di classificazione immagine.

Il modello e' stato creato da un train di Inception

============================================================

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'

import sys

import tensorflow as tf

import tensorflow_hub as hub

from keras.models import load_model

model = tf.keras.models.load_model('incept.h5', custom_objects={'KerasLayer':hub.KerasLayer})
#print(model.get_config())
from keras.preprocessing import image
img = image.load_img(sys.argv[1])# , target_size=(299,299,3))
img  = image.img_to_array(img)
img  = img.reshape((1,) + img.shape)
img  = img/255
build_input_shape = img.reshape(-1,299,299,3)
#print (build_input_shape)
img_class=model.predict_classes(img) 
print (sys.argv[1])
print(img_class) 

mercoledì 8 gennaio 2020

Conversione da formato .pd (saved_model) a tflite

Un file in formato .pb racchiude al suo interno un modello completo di grafo con calcoli e pesi e puo' essere utilizzato direttamente per il serving

Tflite e' invece il formato di TensorFlow Lite ed e' caratterizzato da ridotte dimesioni mediante model quantization e model pruning

Per passare da .pb a .tflite (il contrario non si puo' fare) si possono usare i programmi toco e tflite_converter (il file risultante e' equivalente)


toco --saved_model_dir ./fora --output_file test.tflite
tflite_convert -output_file = model.tflite --saved_model_dir = my_dir 


Nella conversione, a seconda del livello di ottimizzazione, il modello tflite puo' performare in modo uguale od inferiore al modello completo

Esempio Retraining an image classifier

Ho trovato un esempio completo per il retraining di un classificatore di immagini a questo link

https://colab.research.google.com/github/tensorflow/hub/blob/master/examples/colab/tf2_image_retraining.ipynb

Si tratta di un Jupyter Notebook in cui si puo' attivare data augmentation e fine tuning e si puo' scegliere tra MobileNet v2 e Inception v3. I dati presentano gia' uno split con il 20% destinato alla validazione e shuffle del training, shuffle sul training, dropout

Girando su Colab si ha a disposizione una istanza con 12 Gb di Ram ed una GPU da 16 Gb di ram.
Il modello viene salvato nel formato .pb ma puo' essere convertito in formato .tflite con una verifica di quanto si perda in prestazioni utilizzando il formato di TensorFlow Lite

per attivare ogni singola cella di codice si usa CTRL+Enter



il file puo' essere visualizzato, una volta scaricato dal proprio GDrive, con il comando

saved_model_cli show --dir fora2/ --all

----------------------------------------------------------------------------
MetaGraphDef with tag-set: 'serve' contains the following SignatureDefs:

signature_def['__saved_model_init_op']:
  The given SavedModel SignatureDef contains the following input(s):
  The given SavedModel SignatureDef contains the following output(s):
    outputs['__saved_model_init_op'] tensor_info:
        dtype: DT_INVALID
        shape: unknown_rank
        name: NoOp
  Method name is: 

signature_def['serving_default']:
  The given SavedModel SignatureDef contains the following input(s):
    inputs['input_1'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 224, 224, 3)
        name: serving_default_input_1:0
  The given SavedModel SignatureDef contains the following output(s):
    outputs['output_1'] tensor_info:
        dtype: DT_FLOAT
        shape: (-1, 5)
        name: StatefulPartitionedCall:0
  Method name is: tensorflow/serving/predict



Art and Science of Machine Learning





sabato 4 gennaio 2020

Analisi degli errori rete neurale foraminiferi

Aggiornamento

ho visto che il programma label_inmage.py prevede anche degli switch che settano i valori di input_mean e input_std (di default sono impostati a 127.5 entrambi i valori)

modificando questi parametri cambiano anche in maniera sensibili i risultati dello stesso file di modello tflite. Con una configurazione differente non ci sono classi particolarmente penalizzate


allo stesso modo anche make_image_classifier possono essere cambiate le epoch, il learning rate, batch size, momentum (gradient descent)

====================================================================

Questo al momento e' il miglior risultato della rete neurale sui foraminiferi

Si nota abbastanza chiaramente che la classe Globigerinita Glutinata ha un tasso di riconoscimento del tutto errato. Le altre classi hanno prestazioni migliori con risultati intorno al 60% di corrette identificazioni
Per cercare di isolare il problema ho isolato gli errori del set di test


Globigerina Bulloides

Gli score di corretti riconoscimenti sono compresi tra 0.83 e 0.33


GB 280

Globigerina Bulloides 280  scambiata per Globigerinoides Sacculifer  score 0.51

GB 315

Globigerina Bulloides 315  scambiata per  Globigerinoides Ruber   score 0.51

Globigerinita Glutinata 

Gli score di corretti riconoscimenti sono compresi tra 0.59 e 0.35

GG 1406

Globigerinita Glutinata 1406 identificata dalla rete neurale come Globigerina Bulloides con score 0.35. La seconda piu' probabile identificazione con score 0.33 era Gobigerinita Glutinata ovvero la classe corretta

GG 1449
Globigerinita Glutinata 1449 identificata dalla rete neurale come Globigerina Bulloides con score 0.67.

GG 265
Globigerinita Glutinata 265 identificata dalla rete neurale come Neogloboquadrina Pachyderma con score 0.60.

GG 564
Globigerinita Glutinata 564 identificata dalla rete neurale come Neogloboquadrina Pachyderma con score 0.76.

GG 68

Globigerinita Glutinata 68 identificata dalla rete neurale come Globigerinoides Sacculifer con score 0.55.


GG 765
Globigerinita Glutinata 765 identificata dalla rete neurale come Neogloboquadrina Pachyderma con score 0.65.

GG 822
Globigerinita Glutinata 882 identificata dalla rete neurale come Neogloboquadrina Pachyderma 

GG 955
Globigerinita Glutinata 955 identificata dalla rete neurale come Globigerinoides Ruber con score 0.7.

Globigerinoides Ruber


GR 1795


GR 1802

GR 1819
GR 355




Eth0 su LuckFox Pico Mini A

 Le schede Luckfox Pico Mini A (a differenza delle sorelle maggiori) non hanno un connettore RJ45 e nonostante i pin da saldare non sembrano...