venerdì 15 novembre 2019

Preparare i dati per Tensorflow

Questo spero si tratti l'inizio di alcuni post sulla possibilita' di usare Tensorflow per stimare la concentrazione di alcune specie chimiche partendo da spettri IR

Per questo scopo c'e' bisogno di un database in cui sono presenti spettri IR ed analisi composizionali del materiale. L'unico database pubblico che conosco e' usgs_splib07 da questo link

Per semplicita' sono stati selezionati gli spettri a 480 bande


SiO2Al2O3MgO
1Actinolite HS11657,80,2222,4
2Actinolite HS22 54,51,6421,69
3Actinolite HS315 57,71,3824,58
4Albite NMNHC5390 68,1820,070,02
5Almandine HS114 40,422,970,53
6Almandine WS475 37,9822,147,35
7Almandine WS476 39,8422,0410,69
8Almandine WS478 39,0922,055,74
9Almandine WS479 37,3421,938,83
10Andradite NMNH113829 35,50,290,14
11Andradite WS474 35,850,0850,67
12Annite WS661 33,4814,510,006
13Antigorite NMNH96917a41,31,5936,3
14Augite NMNH120049 48,938,4414,37
15Biotite WS660 39,5211,0514,45
16Chlorite SMR-13 3117,330,2
17Clinochlore GDS158 27,519,824,7
18Clinochlore GDS159 31,319,434,7
19Clinochlore NMNH83369 321633,9
20Diopside NMNHR18685 54,770,4918,26
21Elbaite NMNH9421736,8340,560,03
22Epidote GDS26 37,1423,050,06
23Grossular NMNH155371 38,8417,950,15
24Grossular WS484 39,7122,580,019
25Halloysite CM13 46,335,20,31
26Hectorite SHCa-134,70,6915,3
27Hydrogrossular NMNH120555 31,4421,40,17
28Hypersthene NMNHC2368 51,324,8926,09
29Illite GDS4 (Marblehead)51,6223,963,83
30Illite IMt-152,121,92,39
31Kaolinite CM5 44,437,90,11
32Kaolinite CM7 44,636,40,14
33Kaolinite CM9 47,137,40,16
34Kaolinite KGa-1 (wxl)45380,02
35Kaolinite KGa-2 (pxl) 44,237,20,04
36Lizardite NMNHR4687 40,97040,43
37Marialite NMNH126018-259,8820,590
38Meionite WS701 49,625,450,06
39Mizzonite NMNH11377549,625,430,03
40Montmorillonite CM20 5218,363,32
41Montmorillonite CM26 63,418,22,26
42Montmorillonite CM27 57,620,92,66
43Montmorillonite+Illite CM37 46,522,72,74
44Montmorillonite+Illite CM42 54,8213,4
45Montmorillonite SAz-160,417,66,46
46Montmorillonite SCa-2 52,4156,68
47Montmorillonite STx-169,616,33,56
48Montmorillonite SWy-162,919,32,8
49Muscovite GDS108 44350,57
50Nontronite NG-18020,42
51Nontronite SWa-174,67,693,32
52Olivine GDS70 Fo89 41,09049,29
53Olivine GDS71 Fo91 40,06050,7
54Olivine KI3005 Fo11 30,1104,42
55Olivine KI3054 Fo66 36,3032,62
56Olivine KI3188 Fo51 34,34023,8
57Olivine KI3189 Fo60 35,47029,49
58Palygorskite CM46a 5610,68,56
59Pectolite NMNH94865 53,370,030,03
60Phlogopite GDS20 40,314,326,4
61Phlogopite WS496 43,01511,629,62
62Quartz HS117 Aventurine 10000
63Rhodonite NMNHC6148 46,30,050,41
64Richterite NMNH150800 54,871,9722,92
65Saponite SapCa-151,93,660,88
66Sepiolite SepNev-1.AcB 50,90,4522,3
67Talc HS21 60,470,1230,29
68Talc WS659 58,380,1831,9
69Thuringite SMR-1524,721,116,8
70Tremolite NMNH117611 54,61,8823,13
71Vermiculite VTx-1.a19,51,5327,7

I dati sono stati estratti dalla directory ASCIIData/ASCIIdata_splib07a/ChapterM_Minerals selezionando gli spettri denominati BECKb_AREF.
Un esempio di file e'

---------------------------------------
 splib07a Record=120: Actinolite HS116.3B           BECKb AREF
-1.2300000e+034
 3.3700544e-002
 3.5717472e-002
 3.5481069e-002
 3.5344660e-002
 3.4786128e-002
 3.3701397e-002
 3.3403333e-002
 3.3196956e-002
 3.3779550e-002
 3.2682978e-002
 3.3049587e-002
 3.4390874e-002
 3.4718834e-002
 3.6168687e-002
...............................................
---------------------------------------

Si iniziano quindi a preparare i dati per inserirli in un array compatibile con NumPy,formato idoneo al successivo utilizzo con Tensorflow

per prima cosa si toglie la prima riga di intestazione con sed

for f in *.txt ; do sed -i '1d' $f; done

viene quindi eseguito uno script python che legge i dati riga per riga e restituisce una stringa lineare con i dati separati da un punto e virgola

converti.py
=================================
with open("1.txt",'r') as f:
while True:
buf = f.readline()
if not buf:
break
print (buf.strip()),
print ';',
=================================

for f in *.txt ; do python converti.py > a$f; done

i nuovi file avranno il carattere a anteposto al precedente nome file

for f in *.txt ; do python converti.py > a$f; done

si tolgono quindi gli spazi bianchi

for f in a*.txt ; do cat $f  | tr - d "[:space:]" > b$f ; done

i nuovi file avranno il carattere b anteposto al precedente nome file
siamo quasi arrivati alla fine. Ogni file dello spettro e' costituito da un riga, si deve quindi creare un unico file in cui ogni riga rappresenta uno spettro

for f in ba*.txt; do (cat "${f}"; echo) >> completo.txt; done
from numpy import genfromtxt
data = genfromtxt('completo.txt', delimiter=',')


Da notare bene che tensorflow non funziona su macchine con processori non recenti perche' vengono usate delle istruzioni cpu recenti (AVX and AVX2 instruction sets)

Per installare Tensorflow su Debian con virtualenv si usa la sequenza (ripresa da questo sito)

si installa python3
apt-get install python3-venv python3 
mkdir spectra
cd spectra
python3 -m venv venv
source venv/bin/activate
pip install --upgrade pip
pip install --upgrade tensorflow

per verificare l'installazione si usa 

python -c 'import tensorflow as tf; print(tf.__version__)'
per terminare virtualenv si digita

deactivate

A questo punto ho diviso il file di 71 spettri in una serie di train di 60 spettri ed una serie di test di 11 spettri (x_train,x_test) . Per quanto riguarda le concentrazioni il file delle concentrazioni (y_train, y_test) i valori di concentrazioni sono stati divisi in 10 classi con la seguente regola

0-9.9% : classe 0
10-19.9% : classe  1
20-29.9% : classe  2
30-39.9% : classe  3
40-49.9% : classe  4
50-59.9% : classe  5
60-69.9% : classe  6
70-79.9% : classe  7
80-89.9% : classe  8
90-100% : classe  9

per prova ho usato le concentrazioni di SiO2 (uno dei parametri piu' difficili da determinare da uno spettro IR nel rilevamento iperspettrale)

Prima di procedere i valori No data contenuti negli spettri e indicati dal valore -1.2300000e+034 sono stati convertiti in 0

provando con un rete neurale con delle impostazioni  non ottimizzate

==============================================================
import numpy as np
from numpy import genfromtxt

import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers

x_train = genfromtxt("x_train.txt",delimiter=';',usecols=np.arange(0,479))
x_test = genfromtxt("x_test.txt",delimiter=';',usecols=np.arange(0,479))

y_train = genfromtxt("y_train.txt",delimiter=';',usecols=np.arange(0,1))
y_test = genfromtxt("y_test.txt",delimiter=';',usecols=np.arange(0,1))

y_train = y_train.transpose()

#print (x_train)


y_train = y_train.astype(int)
y_test = y_test.astype(int)
#print (y_train)

print ("====================")
print ("X trains" + str(x_train.shape))
print ("Y trains" + str(y_train.shape))
print ("X test" + str(x_test.shape))
print ("Y test" + str(y_test.shape))
print ("====================")

model = tf.keras.Sequential()
model.add(layers.Dense(128,activation='relu'))
model.add(layers.Dropout(0.2))
model.add(layers.Dense(10,activation='softmax'))

model.compile(optimizer='adam',loss='sparse_categorical_crossentropy',metrics=['accuracy'])

model.fit(x_train,y_train,epochs=16)
model.evaluate(x_test,y_test,verbose=2)
==============================================================

il risultato e' il seguente

====================
X trains(60, 479)
Y trains(60,)
X test(11, 479)
Y test(11,)
====================
2019-11-15 13:35:58.075622: I tensorflow/core/platform/cpu_feature_guard.cc:142] Your CPU supports instructions that this TensorFlow binary was not compiled to use: AVX2 FMA
2019-11-15 13:35:58.099810: I tensorflow/core/platform/profile_utils/cpu_utils.cc:94] CPU Frequency: 2294770000 Hz
2019-11-15 13:35:58.100500: I tensorflow/compiler/xla/service/service.cc:168] XLA service 0x38bfc90 executing computations on platform Host. Devices:
2019-11-15 13:35:58.100551: I tensorflow/compiler/xla/service/service.cc:175]   StreamExecutor device (0): Host, Default Version
Train on 60 samples
Epoch 1/16
60/60 [==============================] - 0s 8ms/sample - loss: 2.2551 - accuracy: 0.1000
Epoch 2/16
60/60 [==============================] - 0s 85us/sample - loss: 1.7444 - accuracy: 0.3833
Epoch 3/16
60/60 [==============================] - 0s 90us/sample - loss: 1.6373 - accuracy: 0.3333
Epoch 4/16
60/60 [==============================] - 0s 83us/sample - loss: 1.6465 - accuracy: 0.3167
Epoch 5/16
60/60 [==============================] - 0s 96us/sample - loss: 1.5436 - accuracy: 0.3833
Epoch 6/16
60/60 [==============================] - 0s 127us/sample - loss: 1.6167 - accuracy: 0.3667
Epoch 7/16
60/60 [==============================] - 0s 92us/sample - loss: 1.4574 - accuracy: 0.3833
Epoch 8/16
60/60 [==============================] - 0s 100us/sample - loss: 1.5219 - accuracy: 0.3500
Epoch 9/16
60/60 [==============================] - 0s 81us/sample - loss: 1.4713 - accuracy: 0.4000
Epoch 10/16
60/60 [==============================] - 0s 81us/sample - loss: 1.4284 - accuracy: 0.3500
Epoch 11/16
60/60 [==============================] - 0s 105us/sample - loss: 1.4529 - accuracy: 0.4167
Epoch 12/16
60/60 [==============================] - 0s 107us/sample - loss: 1.3913 - accuracy: 0.4167
Epoch 13/16
60/60 [==============================] - 0s 92us/sample - loss: 1.4574 - accuracy: 0.4000
Epoch 14/16
60/60 [==============================] - 0s 82us/sample - loss: 1.4370 - accuracy: 0.3500
Epoch 15/16
60/60 [==============================] - 0s 80us/sample - loss: 1.4666 - accuracy: 0.3667
Epoch 16/16
60/60 [==============================] - 0s 88us/sample - loss: 1.3726 - accuracy: 0.4500
11/1 - 0s - loss: 3.1148 - accuracy: 0.0000e+00




Impiegando i dati di concentrazione di Mg0 le cose migliorano

60/60 [==============================] - 1s 9ms/sample - loss: 1.8941 - accuracy: 0.3833
Epoch 2/16
60/60 [==============================] - 0s 194us/sample - loss: 1.4062 - accuracy: 0.6500
Epoch 3/16
60/60 [==============================] - 0s 167us/sample - loss: 1.1572 - accuracy: 0.6500
Epoch 4/16
60/60 [==============================] - 0s 187us/sample - loss: 1.1490 - accuracy: 0.6333
Epoch 5/16
60/60 [==============================] - 0s 173us/sample - loss: 1.0612 - accuracy: 0.6333
Epoch 6/16
60/60 [==============================] - 0s 195us/sample - loss: 1.0615 - accuracy: 0.6500
Epoch 7/16
60/60 [==============================] - 0s 193us/sample - loss: 1.0023 - accuracy: 0.6333
Epoch 8/16
60/60 [==============================] - 0s 164us/sample - loss: 1.0067 - accuracy: 0.6667
Epoch 9/16
60/60 [==============================] - 0s 221us/sample - loss: 0.9609 - accuracy: 0.6667
Epoch 10/16
60/60 [==============================] - 0s 185us/sample - loss: 0.9922 - accuracy: 0.6333
Epoch 11/16
60/60 [==============================] - 0s 163us/sample - loss: 0.9188 - accuracy: 0.6333
Epoch 12/16
60/60 [==============================] - 0s 234us/sample - loss: 0.9704 - accuracy: 0.6333
Epoch 13/16
60/60 [==============================] - 0s 176us/sample - loss: 0.9234 - accuracy: 0.6833
Epoch 14/16
60/60 [==============================] - 0s 202us/sample - loss: 0.9051 - accuracy: 0.6833
Epoch 15/16
60/60 [==============================] - 0s 181us/sample - loss: 0.8635 - accuracy: 0.7167
Epoch 16/16
60/60 [==============================] - 0s 171us/sample - loss: 0.8449 - accuracy: 0.7000
11/1 - 0s - loss: 2.3372 - accuracy: 0.2727


lunedì 11 novembre 2019

Mandelbrot in 67 secondi su C64

Riuscire a calcolare l'insieme di Mandelbrot su un C64 e' stata una dellle sfide (perse) di quando ero ragazzo e leggevo Dewdney su Le Scienze


Adesso dopo tanti anni sono arrivato a 67 secondi  e sotto al minuto usando ottimizzazioni un po' piu' spinta (si perde pero' la cuspide del cardioide). Ulteriori miglioramenti possono essere fatti abbassando il limite massimo della variable k e usando una lookup table dei quadrati gia' calcolata

Per il calsolo sono stati utilizzati i seguenti sistemi

1) Emulazione Vice 3.3 al 100% di velocita' per emulare un C64 reale
2) Uso della tabella di lookup dei quadrati
3) Matematica a numeri interi
4) Algoritmo di calcolo che non prevede moltiplicazioni ma solo somme e sottrazioni
5) Uso di eseguibile compilato con CC65
6) Uso della simmetria


Massima ottimizzaziona impiegata con perdita della cuspide del cardioide
L'algoritmo e' quello gia' visto qui . Ottimizzazione del controllo sul cardiode da Wikipedia


da compilare con

cl65 -O -o "mande.prg" - t c64 --static-locals fractint.c

in giallo l'ottimizzazione del controllo sul cardioide

per migliorare gli algoritmi si puo' fare riferimento al seguente link

===========fractint.c===============
#include <stdio.h>
#include <stdlib.h>
#include <cc65.h>
#include <conio.h>
#include <tgi.h>


static void Mand (void)
{

    static const unsigned char Palette[2] = { TGI_COLOR_WHITE, TGI_COLOR_ORANGE };
    register unsigned s,k;
    register int zi,zr,jr,ji,a,test;
    int q[180];

    tgi_setpalette (Palette);
    tgi_setcolor (1);

    for (s=1; s<170;s++)
{
q[s] = (int) (s*s/32);
}

    for (jr=-63;jr<18;jr++)
{
for (ji=-63; ji<1;ji++)
{
zi = zr = 0;

test = q[abs(jr-8)] + q[abs(ji)];
if (test*(test+(jr-8)) >  (q[abs(ji)]/4))

{
for (k=0; k<=25;k++)
{
a = q[abs(zr)] - q[abs(zi)] + jr;
zi = q[abs(zr)]+q[abs(zi)]-q[abs(zr-zi)]+ji;
zr = a;
if (q[abs(zr)] + q[abs(zi)] >  128 )
{
tgi_setcolor(k%2);
tgi_setpixel(jr+64,ji+64);
tgi_setpixel(jr+64,128-abs(63+ji));
k=26;
}
}
}
}
}

    cgetc ();
    tgi_clear ();
}



int main (void)
{

    tgi_load_driver (tgi_stddrv);
    tgi_init ();
    tgi_clear ();

    Mand();

    tgi_unload ();
    return EXIT_SUCCESS;
}

CC65 Tgidemo su Vice x64

Il compilatore CC65 permette di scrivere programmi in modalita' grafica mediante TGI ma non ero mai riuscito a farli poi eseguire dall'emulatore/C64 perche' l'eseguibile non riusciva a trovare la libreria grafica...la soluzione e' quella di creare un disco virtuale in cui copiare la libreria virtuale ed il file PRG


Si puo' iniziare compilando la demo con il comando

../bin/cl65 -O -o "tgidemo.prg"  -t c64 tgidemo.c

A questo punto con il comando c1541 (incluso in Vice) si crea un nuovo disco e si copiano i file tgidemo.prg e c64-hi.tgi

c1541 -format diskname,id d64 my_diskimage.d64 -attach my_diskimage.d64 -write tgidemo.prg
c1541 -attach my_diskimage.d64 -write c64-hi.tgi

dall'emulatore si seleziona Autostart Image ..si vedra' un messaggio "This program needs...." si preme y e si attende qualche secondo
A questo punto apparira' la schermata dell'immagine soprastante

martedì 5 novembre 2019

Buildroot e Raspberry Pi

Con BuildRoot e' possibile compilare un firmware completo per un dispositivo embedded...per fare le cose semplici ho provato con Raspberry Pi

Si clona il repository di Buildroot e si lancia

make raspberrypi_defconfig
che preimposta i valori di default per il target Raspberry. Si possono aggiungere sia pacchetti che librerie per personalizzare la configurazione base cosi' come la password di root (System Configuration/Enable root login with password)

Si lancia make e si aspetta un paio di ore...alla fine nella directory output/images si trovera' file sdcard.img 

si puo' quindi copiare il file su una Sd Card con dd ed usare una Raspberry reale oppure si puo' emulare tramite QEmu
Per fare cio' si deve scaricare il kernel per QEmu da

git clone https://github.com/dhruvvyas90/qemu-rpi-kernel.git

e si lancia

qemu-system-arm -kernel ./qemu-rpi-kernel/kernel-qemu-3.10.25-wheezy -cpu arm1176 -m 256 -M versatilepb -no-reboot -serial stdio -append "root=/dev/sda2 panic=1 rootfstype=ext4 rw" -hda sdcard.img


ci si trova quindi in una shell Busybox

Femore di cervo

Cercando funghi mi sono imbattuto in questo osso semi sepolto. Da una verifica con l'articolo riportato per riferimento alla fine di questo post sembra essere attribuibile ad un femore di cervo, forse un cucciolo viste la modesta lunghezza















lunedì 4 novembre 2019

Librerie con buildroot

per continuare il post precedente volevo provare a cross compilare  linkando delle librerie dinamiche.
Il progetto Buildroot rende disponibile un plugin per Eclipse ma e' disponibile solo per Eclipse Luna mentre attualmente e' disponibile la versione 2019 (dove il plugin non funziona)



Se si prova  scaricare Eclipse Luna e si cerca di esesguirlo su una Debian 11 non fuzionera' perche' necessita di JDK 11 (su Debian Java 8 e' stato rimosso e di default e' disponibile Java 11).
Non e' possibile usare i repository ufficiali per fare il downgrade per cui' ci si deve appoggiare ad un repository esterno con in comandi


sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv-keys 0xB1998361219BD9C9 
echo "deb http://repos.azulsystems.com/debian stable main" | sudo tee /etc/apt/sources.list.d/zulu.list
apt-get install zulu-8

fatto cio' In Help/Install New Software di Eclipse di aggiunge il link

http://buildroot.org/downloads/eclipse/luna

e si installa il plugin Buildroot

Come esempio si puo' provare a linkare in modo dinamico la libreria ZLib
Da make menuconfig di BuildRoot si spunta Register Toolchain within Eclipse dal menu Toolchain


dopo di cio' Target packages/Libraries/Compression/ si seleziona Zlib

si esce si effettua il make

Si ritorna ad Eclipse File/New/Project/Empty Project/Buildroot MIPS e si crea un nuovo file incollando questo esempio https://github.com/madler/zlib/blob/master/test/example.c

Per abilitare la libreria si va in Project Settings/C C++ Build/Settings e si scorre verso destra dal tab Tool Settings fino a trova Pkg-config e si seleziona zlib



L'eseguibile compilato (con il comando file) dovra' contenere la seguente stringa
h5: ELF 32-bit MSB executable, MIPS, MIPS32 version 1 (SYSV), dynamically linked, interpreter /lib/ld-uClibc.so.0, with debug_info, not stripped

Si fa quindi Build e si sposta il progetto sulla Arduino Yun in scp, si cambiano i permessi per l'esecuzione

warning: different zlib version
zlib version 1.2.11 = 0x12b0, compile flags = 0x55
uncompress(): hello, hello!
gzread(): hello, hello!
gzgets() after gzseek:  hello!
inflate(): hello, hello!
large_inflate(): OK
after inflateSync(): hello, hello!
inflate with dictionary: hello, hello!
root@Yun2:~# ldd ./h5
libz.so.1 => /usr/lib/libz.so.1 (0x77124000)
libc.so.0 => /lib/libc.so.0 (0x770b8000)
libgcc_s.so.1 => /lib/libgcc_s.so.1 (0x77095000)
ld-uClibc.so.0 => /lib/ld-uClibc.so.0 (0x77146000)

una volta in esecuzione il programma gira anche se si lamenta di una differenza di librerie tra quella linkata da buildroot e quella effettivamente presente sulla Yun

Se si prova a compilare con ncurses la cosa diventa piu' seria perche' buildroot linka contro ncurses 6 mentre su Yun opkg rende disponibili libncurses 5.7.5 ed il programma non si avvia 

venerdì 1 novembre 2019

Cross compilare da Debian per Arduino Yun

Seguendo il precedente post su come poter continuare ad usare Yun nonostante il supporto end-of-life sono riuscito a settate la possiblita' di effettuare la cross compilazione da Debian verso Yun

Per prima cosa si scarica Buildroot  e lo si  configura (make menuconfig) con target MIPS big endian, ELF MIPS32 con toolchain uCLIb abilitando con Gdb per futuri sviluppi. Fatto cio' si lancia make e si aspetta

A questo punto per rendere piu' semplice la cross compilazione si usa Eclipse CDT
Si crea un nuovo progetto C con Cross GCC e si lasciano in bianco GCC Cross Command che saranno compilati in seguito

Si aprono quindi le proprieta' del progetto Eclipse selezionando Cross GCC in ToolChain Editor


Si setta come Prefix (attenzione al meno finale che deve essere incluso) e Path

mips-buildroot-linux-uclibc-
/home/luca/Downloads/buildroot-2019.02.6/output/host/usr/bin



A questo punto C Build Settings/Includes si include la directory

/home/luca/Downloads/buildroot-2019.02.6/output/host/usr/include  

tutti i file necessari si trovano nella sottodirectory /output/host/ di Buildroot



Si aggiungono due pathe per le librerie

/home/luca/Downloads/buildroot-2019.02.6/output/host/usr/lib
/home/luca/Downloads/buildroot-2019.02.6/output/host/mips-buildroot-linux-uclibc/lib



Arrivati fino a qui si puo' compilare il file e copiarlo in scp sulla Yun

Debugger integrato ESP32S3

Aggiornamento In realta' il Jtag USB funziona anche sui moduli cinesi Il problema risiede  nell'ID USB della porta Jtag. Nel modulo...