giovedì 9 dicembre 2021

LSTM Time Series con Tensorflow per la geologia

Questo post e' un tentativo di applicazione delle reti neurali LSTM per l'analisi di dati (sulla base di questo articolo) derivanti da un sensore ad applicazione geologica, nello specifico un estensimetro. I dati sono dati reali che sono stati anonimizzati ma sono relativi ad un movimento di versante attivo. Sono originali sono acquisiti con passo di 20 minuti e coprono circa 10 mesi e prevedono misure anche meteo

Il primo tentativo e' stato quello di esaminare la curva completa ma presto mi sono reso conto che la rete neurale non riusciva mai a convergere. Ho limitato i dati quindi dall'inizio fino alla primo movimento avvenuto l'8 maggio

Come si osserva dal grafico ridotto sottostante oltre ad un trend generale in crescita dei valori dell'estensimetro vi sono variazioni cicliche a scala corta

in generale le variazioni cicliche a breve periodo di un estensimetro sono relative a dilatazioni termiche
Plottando i dati si ha comunque una scarsa correlazione



Un approccio di analisi base prevede di trovare una curva che approssima i dati (in questo caso la migliore approssimazione e' stata una polinomio di secondo grado)

facendo uno zoom si ha vede che le variazioni a breve periodo non sono sinusoidali (in pratica si osserva solo dei picchi di discesa ) e che approssimando con la curva di interpolazione si ha una fascia di incertezza dell'ordine di 1 mm

Vediamo se analizzando la serie tempo con una rete LSTM in Tensorflow si riesce ad ottenere un modello che fitta meglio con i dati

Per prima cosa devo dire che i primi tentativi sono stati piuttosto deludenti..mi sono trovato spesso in situazioni in cui la loss dei dati di training era ottima mentre era pessima  (e spesso in crescita con le epochs) quella del set di validazione. 
In altri casi mi sono trovato ad avere un modello decente che aveva un offset costante rispetto ai dati di controllo (vedi grafico sottostante)


Una soluzione e' stata quella di inserire dei layer di dropout nella rete e quella di effettuare un detrending (sottrarre ai dati grezzi il valore della funzione che approssima la tendenza generale)

Un altro aspetto determinante per un modello ottimale consiste nell'individuazione della corretta batch size (nel caso specifico batch size inferiore a 50 non riusciva a seguire le variazioni dei dati)

un dettaglio dei dati dopo il detrend



il miglior risultato che sono riuscito ad ottenere e' il seguente
questi sono i dati di train contro dati reali. Si nota che il modello segue l'andamento dei dati reali ma mostra un ritardo nei minimi relativi del trend generale
 

questi sono invece i dati di validazione. Si osserva una buona sincronia sulle variazioni a breve periodo


========================================
# -*- coding: utf-8 -*-
"""Quincineto_stima_errore_detrend2.ipynb

Automatically generated by Colaboratory.

Original file is located at
https://colab.research.google.com/drive/1fFEfuUj5iwNucKDOfVpEzvIYK_1KebH8

### Elaborazione Quincineto
"""

import pandas as pd
import numpy as np
from sklearn.preprocessing import MinMaxScaler
import matplotlib.pyplot as plt
import tensorflow as tf
import os

# Commented out IPython magic to ensure Python compatibility.
#prepara tensorboard
# %load_ext tensorboard

"""
Download dati"""

!wget http://c1p81.altervista.org/detrend2.zip

!unzip detrend2.zip

"""Carica i dati in matrice"""

df=pd.read_csv(r'detrend2.csv', sep=',', header=0,index_col=['Data'])
df.head()

plt.plot(df['Est.[mm]'])
plt.title("Estensimetro")
plt.xlabel('Datetime')
plt.ylabel('Est')
plt.show()

#finestra mobile dei dati
n_past = 300
n_future = 100
n_features = 1

# divide il dataset in 75% train, 25 % test
righe = df.shape[0]
t = np.round(righe*0.75,0)
print(t)
train_df,test_df = df[1:6000], df[6000:]

# il dataset di test non entra nel calcolo della rete neurale
# e' lo stato futuro che la rete deve prevedere
# qui si trova la rottura della tendenza
plt.plot(test_df['Est.[mm]'])
plt.title("Train dataset estensimetro Dettaglio")
plt.xlabel('Datetime')
plt.ylabel('Est')
plt.show()

#riscala i dati per il calcolo della rete
train = train_df
scalers={}

for i in train_df.columns:
scaler = MinMaxScaler(feature_range=(-1,1))
s_s = scaler.fit_transform(train[i].values.reshape(-1,1))
s_s=np.reshape(s_s,len(s_s))
scalers['scaler_'+ i] = scaler
train[i]=s_s

test = test_df
for i in train_df.columns:
scaler = scalers['scaler_'+i]
s_s = scaler.transform(test[i].values.reshape(-1,1))
s_s=np.reshape(s_s,len(s_s))
scalers['scaler_'+i] = scaler
test[i]=s_s

"""**Converting the series to samples for supervised learning**"""

def split_series(series, n_past, n_future):
#
# n_past ==> no of past observations
#
# n_future ==> no of future observations
#
X, y = list(), list()
for window_start in range(len(series)):
past_end = window_start + n_past
future_end = past_end + n_future
if future_end > len(series):
break
# slicing the past and future parts of the window
past, future = series[window_start:past_end, :], series[past_end:future_end, :]
X.append(past)
y.append(future)

return np.array(X), np.array(y)

X_train, y_train = split_series(train.values,n_past, n_future)
X_train = X_train.reshape((X_train.shape[0], X_train.shape[1],n_features))
y_train = y_train.reshape((y_train.shape[0], y_train.shape[1], n_features))

X_test, y_test = split_series(test.values,n_past, n_future)
X_test = X_test.reshape((X_test.shape[0], X_test.shape[1],n_features))
y_test = y_test.reshape((y_test.shape[0], y_test.shape[1], n_features))

X_test.shape
print(train)

# E1D1
# n_features ==> no of features at each timestep in the data.
#
encoder_inputs = tf.keras.layers.Input(shape=(n_past, n_features))
encoder_l1 = tf.keras.layers.LSTM(300, return_state=True)
encoder_outputs1 = encoder_l1(encoder_inputs)
encoder_states1 = encoder_outputs1[1:]
#
decoder_inputs = tf.keras.layers.RepeatVector(n_future)(encoder_outputs1[0])
#
decoder_l1 = tf.keras.layers.LSTM(300, return_sequences=True,dropout=0.5,recurrent_dropout=0.5)(decoder_inputs,initial_state = encoder_states1)
decoder_outputs1 = tf.keras.layers.TimeDistributed(tf.keras.layers.Dense(n_features))(decoder_l1)
#
model_e1d1 = tf.keras.models.Model(encoder_inputs,decoder_outputs1)

model_e1d1.summary()

reduce_lr = tf.keras.callbacks.LearningRateScheduler(lambda x: 1e-3 * 0.90 ** x)

epoche = 15

#tensorboard start
import datetime
log_dir = "Logs/fit/" + datetime.datetime.now().strftime("%Y%m%d-%H%M%S")
tensorboard_callback = tf.keras.callbacks.TensorBoard(log_dir=log_dir, histogram_freq=1)
#tensorboard start

model_e1d1.compile(optimizer=tf.keras.optimizers.Adam(), loss=tf.keras.losses.Huber())
history_e1d1=model_e1d1.fit(X_train,y_train,epochs=epoche,validation_data=(X_test,y_test),batch_size=164,verbose=1,callbacks=[reduce_lr,tensorboard_callback])

plt.plot(history_e1d1.history['loss'])
plt.plot(history_e1d1.history['val_loss'])
plt.title("Model Loss")
plt.xlabel('Epochs')
plt.ylabel('Loss')
plt.legend(['Train', 'Valid'])
plt.show()

plt.plot(history_e1d1.history['lr'])
plt.title("Model Lr")
plt.xlabel('Epochs')
plt.ylabel('Lr')
plt.show()

"""Predizione dei dati"""

pred1_e1d1=model_e1d1.predict(X_test)
pred_e1d1=model_e1d1.predict(X_train)

"""Ritorna dai valori scalati ai valori reali"""

for index,i in enumerate(train_df.columns):
scaler = scalers['scaler_'+i]
pred1_e1d1[:,:,index]=scaler.inverse_transform(pred1_e1d1[:,:,index])
pred_e1d1[:,:,index]=scaler.inverse_transform(pred_e1d1[:,:,index])
y_train[:,:,index]=scaler.inverse_transform(y_train[:,:,index])
y_test[:,:,index]=scaler.inverse_transform(y_test[:,:,index])

#print(y_train)
np.savetxt('array_ytrain_X.csv', y_train[:,:,0], delimiter=';', fmt='%f')
np.savetxt('array_ytrain_Y.csv', y_train[:,:,1], delimiter=';', fmt='%f')
np.savetxt('array_ytrain_Est.csv', y_train[:,:,2], delimiter=';', fmt='%f')
np.savetxt('array_ytrain_T.csv', y_train[:,:,3], delimiter=';', fmt='%f')
np.savetxt('array_ytrain_bat.csv', y_train[:,:,4], delimiter=';', fmt='%f')

np.savetxt('array_ytest_X.csv', y_test[:,:,0], delimiter=';', fmt='%f')
np.savetxt('array_ytest_Y.csv', y_test[:,:,1], delimiter=';', fmt='%f')
np.savetxt('array_ytest_Est.csv', y_test[:,:,2], delimiter=';', fmt='%f')
np.savetxt('array_ytest_T.csv', y_test[:,:,3], delimiter=';', fmt='%f')
np.savetxt('array_ytest_bat.csv', y_test[:,:,4], delimiter=';', fmt='%f')

print(pred1_e1d1[:,:,0])

"""**Checking Error** """

#errore medio tra modello e dati reali
from sklearn.metrics import mean_absolute_error
print(y_test.shape)
#print(pred1_e1d1[:,:,2])
#print(y_test[:,:,2])
#print(y_test.shape[0])
diff = pred1_e1d1[:,:,0]-y_test[:,:,0]
print("Diff")
#print(diff)
print(diff.shape)
#print(np.square(diff))
sommaq=np.sum(np.square(diff[0]))
print(sommaq.shape)
s_err1=np.sqrt(sommaq/y_test.shape[0]*y_test.shape[1])
print()
print(sommaq)
#err1 = np.square(pred1_e1d1[:,:,2]-y_test[:,:,2])
#s_err1 = np.sqrt(np.sum(err1, axis=0))
#print("Errore quadratico medio (mm)")
print(s_err1)

#print(y_test)
plt.plot(y_test[:,99,0])
plt.plot(pred1_e1d1[:,99,0])
plt.title("Modello vs monitoraggio")
plt.xlabel('Tempo')
plt.ylabel('Est')
plt.legend(['Dati reali', 'Modello'])
plt.show()

# Modello contro monitoraggio nei dati di addestramento
plt.plot(y_train[:,99,2])
plt.plot(pred_e1d1[:,99,2])
plt.title("")
plt.xlabel('Tempo')
plt.ylabel('Est (mm)')
plt.legend(['Monitoraggio', 'Modello'])
plt.show()

# dettaglio del grafico Modello contro dati reali
# si nota come il modello copia in modo idoneo anche
# le variazioni a corto periodo
plt.plot(y_train[1:1000,99,2])
plt.plot(pred_e1d1[1:1000,99,2])
plt.title("")
plt.xlabel('Tempo')
plt.ylabel('Est (mm)')
plt.legend(['Monitoraggio', 'Modello'])
plt.show()

# Commented out IPython magic to ensure Python compatibility.
# %tensorboard --logdir Logs/fit


Utilizzando l'esempio del Time Series Forecasting direttamente dal sito di Tensorflow si hanno risultati similari




giovedì 2 dicembre 2021

Dante e Tensorflow

 Questa storia viene da lontano. Al liceo il professore di italiano mi diede un floppy disk da 5 1/4 con una versione digitale della Divina Commedia dicendomi che era possibile una analisi delle ricorrenze delle parole per vedere come cambiava lo stile di scrittura di Dante Alighieri passando da Inferno, Purgatorio e Paradiso


Un lettore umano capisce subito la differenza tra i vari canti...ma un computer?

Dopo tanti anni e' arrivato il momento di fare un test con una rete neurale.

La prova e' stata quella di utilizzare l'esempio di Text Classification di Tensoriflow per vedere se una rete neurale e' capace di distinguere lo stile dantesco (i dati di base sono scaricabili da qui)

La prima prova e' stata quella di usare come train data files che contenevano un intero canto (34 per Inferno e 33 per Paradiso) ma per la scarsita' di dati il modello matematico non convergeva

Sono stati creati quindi files di testo di una sola riga (un solo verso) con un train di 4291 versi dell'Inferno e 4477 versi del Paradiso (i canti XIII e XIV di Inferno e Paradiso sono stati utilizzati come test data)





La rete non ha una accuratezza eccessiva ma e' ben al di sopra del 50% (valore che si otterrebbe tirando a caso nella classificazione) 

se la divisione del testo avviene per terzine il sistema migliora fino ad una accuratezza del 80%










Maratona FIrenze 2021

 Anche quest'anno un posto in prima fila (omino con giacca celeste)




martedì 30 novembre 2021

Mandelbrot M1 Metal Python

 Dopo il test di Cuda e' arrivato il momento di Metal, il linguaggio per la GPU di Apple

Gli ersempi in C++ sono un po' complicati per una semplice prova ed ho optato per la versione in Python in cui il kernel e' comunque scritto in C++ MetalCompute (negli esempi della libreria c'e' gia' una implementazione di Mandelbrot, l'ho scritta da zero per imparare...sicuramente la mia versione e' meno efficiente)


La logica seguita e' quella di Cuda, ogni thread si occupa di una riga

Si puo' solo passare un solo parametro come array di float al kernel e si ha in uscita un solo array di float. L'array di input e' generato con NumPy con le coordinate X,Y dei punti dell'insieme 


import metalcompute as mc
from PIL import Image as im

mc.init()

code = """
#include <metal_stdlib>
using namespace metal;

kernel void mandelbrot(
const device float* arr [[ buffer(0) ]],
device float* out [[ buffer(1) ]],
uint id [[ thread_position_in_grid ]]) {
float a = arr[id];
float b;
float x_new,y_new,x,y;
int iterazioni = 255;

for (int s=0; s<640;s++)
{
x=0.0;
y=0.0;
b = arr[640+s];

for (int k=0;k<iterazioni;k++)
{
x_new = (x*x)-(y*y)+a;
y_new = (2.0*x*y)+b;
if (((x_new*x_new)+(y_new*y_new))>4)
{
out[id*640+s] = (float)(k%2)*255;
k=iterazioni;
}
x = x_new;
y = y_new;
}
}
}
"""
mc.compile(code, "mandelbrot")
import numpy as np
from time import time as now

dimensioni = 640
x_start = -2.0
x_stop = 0.75
x_res = (x_stop-x_start)/dimensioni
x = np.arange(start=x_start, stop=x_stop,step = x_res,dtype='f')

y_start = -1.5
y_stop = 1.5
y_res = (y_stop-y_start)/dimensioni
y = np.arange(start=y_start, stop=y_stop,step = y_res,dtype='f')

arr = np.concatenate((x,y))
print(arr.shape)

out_buf = np.empty(dimensioni*dimensioni,dtype='f')

start = now()
mc.run(arr, out_buf, dimensioni)
end = now()

immagine = out_buf.reshape(dimensioni,dimensioni)
print(end-start)

immagine = np.int_(immagine)
np.savetxt("dati.txt",immagine.astype(int),fmt='%i')

img = im.fromarray(np.uint8(immagine) , 'L')
img.save('m1.png')
img.show()

lunedì 29 novembre 2021

Twitter query API 2

 Con un account sviluppatore di Twitter si possono effettuare query sul DB Twitter

Vi sono limitazioni temporrali (non si puo' andare piu' indietro di una settimana con l'account base) e si possono richiedere da 10 a 100 risultati (questa limitazione si supera utilizzando il valore di next_token contenuto nel risultato della query che permette di effettuare una ulteriori query sui risultati successivi)


import requests
import json
import re
import random

BEARER_TOKEN = "AAAAAAAAAAAAAAAXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

def write_2_file(stringa):
textfile = open(str(random.randrange(1,10000000000))+".txt", "w")
textfile.write(stringa)
textfile.close()

def search_twitter(query, tweet_fields, max_results,next_token, bearer_token = BEARER_TOKEN):
headers = {"Authorization": "Bearer {}".format(bearer_token)}
if len(next_token)>13:
url = "https://api.twitter.com/2/tweets/search/recent?query={}&{}&{}&{}".format(query, tweet_fields,max_results,next_token)
else:
url = "https://api.twitter.com/2/tweets/search/recent?query={}&{}&{}".format(query, tweet_fields,max_results)
response = requests.request("GET", url, headers=headers)
if response.status_code != 200:
raise Exception(response.status_code, response.text)
return response.json()

nr = 100 #numero risultati per query
query = "frana"
tweet_fields = "tweet.fields=text"
max_results = "max_results="+str(nr) #valori compresi tra 10 e 500

start_time = "" # si possono inserire intervalli temporali negli ultimi 7 giorni
end_time = "" # formato YYYY-MM-DDTHH:mm:ssZ (ISO 8601/RFC 3339)

next_token = ""


json_response = search_twitter(query=query, tweet_fields=tweet_fields, max_results=max_results, next_token=next_token, bearer_token=BEARER_TOKEN)
for t in range(nr):
print(re.sub('[^A-Za-z0-9 ]+', '', json_response['data'][t]['text']))
write_2_file(re.sub('[^A-Za-z0-9 ]+', '', json_response['data'][t]['text']))

for i in range(50):
next_token = "next_token="+json_response['meta']['next_token']
json_response = search_twitter(query=query, tweet_fields=tweet_fields, max_results=max_results, next_token=next_token, bearer_token=BEARER_TOKEN)
for t in range(nr):
print(re.sub('[^A-Za-z0-9 ]+', '', json_response['data'][t]['text']))
write_2_file(re.sub('[^A-Za-z0-9 ]+', '', json_response['data'][t]['text']))

mercoledì 24 novembre 2021

Tensorflow su Apple M1 Metal

Ho provato Tensorflow su M1 ed ha una velocita' imbarazzante...ci sono ancora alcuni problemi da risolvere ma la velocita' di M1 e' comparabile se non migliore delle GPU NVidia

Per installarlo si puo' usare le istruzioni a questo link

python3 -m venv ~/tensorflow-metal 
source ~/tensorflow-metal/bin/activate 
python -m pip install -U pip
chmod +x ~/Downloads/Miniforge3-MacOSX-arm64.sh sh
~/Downloads/Miniforge3-MacOSX-arm64.sh 
source ~/miniforge3/bin/activate
conda install -c apple tensorflow-deps
conda install -c apple tensorflow-deps==2.5.0
python -m pip install tensorflow-macos
python -m pip install tensorflow-metal

(ho installato la 2.5.0 per problemi con la 2.6 su reti che gia' usavo su altre macchine)



Per confronto lo stesso addestramento di rete neurale eseguito su M1 ha impiegato 109 secondi. Su una NVidia Quadro K620M (tensorflow-gpu dockerizzato su Linux) ha impiegato 346 secondi. Su un I7-5500 4 core il medesimo calcolo ha impiegato 1684 secondi 

martedì 23 novembre 2021

Foraminifera tensorflow retraining inception

 Un tentativo con risultati migliori di effettuare il riconoscimento di foraminiferi mediante rete neurale

Stavolta ho usato il retraining di Inception V3 usando le immagini che possono essere scaricate da qui (fonte http://endlessforams.org/)

Si tratta di 24 specie con foto a risoluzione di 1 pixel/micron




in totale il dataset e' formato da 3685 immagini di cui 80% di training e 20% di validazione


Il notebook puo' essere visualizzato su Github all'indirizzo


Il valore di batch ottimale e' compreso tra 32 e 40 per valori superiori non ci sono significativi miglioramenti...al di sotto degrada rapidamente




Come si osserva il modello performa quasi perfettamente sul training dataset (dato non interessante) mentre ha un riconoscimento compreso tra un minimo dell'80% ad un massimo del 90% sul dataset di validazione con un netto miglioramento delle prove precedenti







giovedì 18 novembre 2021

Mandelbrot Cuda su Nvidia Jetson Nano

Ho ripreso in mano la scheda Jetson Nano per iniziare a programmare in CUDA 

Gli esempi di CUDA hanno gia' un sorgente per l'insieme di Mandelbrot ma visto che era a scopo didattico sono partito da zero


L'idea e' quella di usare la GPU per i calcoli. Ogni thread calcola una riga dell'immagine. Visto che ogni block della Nvidia puo' gestire al massimo 1024 thread la massima dimensione che il sorgente puo' generare e' 1024x1024

Per condividere una memoria tra la GPU e la CPU (ognuna puo' accere solo alle proprie risorse) si usa  cudaMallocManaged. CudaMemset port i valori della matrice tutti a zero


la funzione kernel e'e quella che viene eseguita dalla GPU. Una volta lanciato il kernel la GPU restituisce il controllo alla CPU solo quando tutti i threads sono terminati. La variabile threadIdx viene utilizzate come indice di colonna dell'immagine

al termine l'array viene convertito in una immagine ppm a scala di grigio (nello specifico si sono solo due colori)

per compilare si usa nvcc con gli switch per indicano la compilazione sull'architettura 50 (relativa alla GPU sulla Jetson) con l'ottimizzazione fast_math

nvcc -use_fast_math -arch=sm_50 mand.cu -o mand

Ho usato VSCode con il terminale ma per programmare Cuda si puo' usare NSight (una versione di Eclipse con plugin NVidia) contenuto nei Cuda Tools

questo il codice

#include <stdio.h>
#include <time.h>

__global__ void kernel (int max, char *matrice)

{
int id = threadIdx.x;

/*zoom1
const double CxMin=-0.3041;
const double CxMax=-0.1874;
const double CyMin=-0.8867;
const double CyMax=-0.7699;*/

/*zoom2*/
const double CxMin=-0.2;
const double CxMax=-0.074;
const double CyMin=-1.058;
const double CyMax=-0.933;

/*insieme completo
const double CxMin=-2.5;
const double CxMax=1.5;
const double CyMin=-2.0;
const double CyMax=2.0;*/
const int iterazioni = 4096;
double x_new,y_new,x,y;
double a,b;

double PixelWidth=(CxMax-CxMin)/max;
double PixelHeight=(CyMax-CyMin)/max;

for (int s=0;s<max;s++)
{
x = 0;
y = 0;
a = CxMin + (PixelWidth*id);
b = CyMin + (PixelHeight*s);
for (int k=0;k<iterazioni;k++)
{
x_new = (x*x)-(y*y)+a;
y_new = (2*x*y)+b;
if (((x_new*x_new)+(y_new*y_new))>4)
{
// colora il punto
matrice[id*max+s] =(k%2)*255;
k=iterazioni;
}
x = x_new;
y = y_new;
}
}
}

int main(void)
{

clock_t tic = clock();
// crea la matrice in GPU
int dimensione = 1000;
char *matcuda;
// crea un array Cuda
cudaMallocManaged(&matcuda,dimensione*dimensione*sizeof(char));
// azzera tutti i valori dell'array
cudaMemset(matcuda,0,dimensione*dimensione*sizeof(char));

// 1024 e' il numero di threads che vengono eseguiti in contemporanea
// e' il valore massimo per ogni block della NVidia
// tra parentesi si possono passare variabili al kernel
kernel <<<1, dimensione>>>(dimensione,matcuda);
cudaDeviceSynchronize();
clock_t toc = clock();
/*
for (int s=0;s<dimensione;s++)
{
for (int t=0;t<dimensione;t++)
{
printf("%i",matcuda[(dimensione*s)+t]);
}
printf("\n");
}
*/
printf("Elapsed: %f seconds\n", (double)(toc - tic) / CLOCKS_PER_SEC);

FILE *fpi = fopen("mand.ppm", "wb");
fprintf(fpi, "P5\n%d %d\n255\n", dimensione, dimensione);
fwrite(matcuda, 1, dimensione*dimensione, fpi);
fclose(fpi);


cudaFree(matcuda);
return 0;
}

sabato 13 novembre 2021

Foraminifera tensorflow retraining

Dopo oltre un anno da questo post ho provato ad affrontare il riconoscimento di foraminiferi mediante rete neurale partendo dal retraining di una rete esistente piuttosto che creando una rete ex novo






Stavolta per rendere i risultati piu' coerenti ho utilizzato solo le immagini al microscopio cono risoluzione di un pixel per micron. Le immagini riprese sempre da endlessforam.org sono state private delle note utilizzando il comando mogrify di imagemagick

Per evitare di installare tutto da zero ho montato tensorflow in docker con il supporto dei notebook di jupyter

docker pull tensorflow:latest-jupyter 

dato che nel docker non e' presente la libreria tensorflow-hub ho modificato il docker creando il Dockerfile 

----------------------------------------

FROM tensorflow/tensorflow:latest-jupyter
RUN pip install --upgrade pip
RUN pip install --upgrade tensorflow-hub

----------------------------------------

in seguito 

docker build . -t tensorflor/tensorflow:latest-jupiter-hub

la rete neurale ha necessita' di occupare piu' Ram possibile ed ho disabilitato i controlli del kernel su docker in modo da non andare in OOM (Out of Memory)

La home directory della macchina e' inoltre mappata su /tf/notebook del container in modo da salvare i modelli. Infine si mappa la porta 8888 del container sulla 8888 del localhost per interagire con i notebook

sudo docker run --oom-kill-disable -m="6g" --memory-swap="10g"  -it -v $PWD:/tf/notebooks -w /tmp -p 8888:8888 tensorflow/tensorflow:latest-jupyter-hub

in alcuni casi puo' essere necessario aggiungere al file /etc/default /grub la stringa

GRUB_CMDLINE_LINUX="cgroup_enable=memory swapaccount=1"

lanciare un update-grub e riavviare la macchina

per abilitare la GPU NVidia si aggiunge lo switch --gpus all ma in questo caso la memoria utilizzabile sara' solo quella della GPU (e sui portatili di solito e' difficile avere schede grafiche con generose dotazioni di ram) e deve essere presente docker-nvidia

Le immagini dei foarminifei sono relativi a 15 classi (dati)

Usando come base efficientnetv2-s-21k-ft1k (dimensione immagine 384 pixel) con il risultato di 80% di risultati corrispondenti sul modello originale  e 68% sul dataset di validazione

il notebook puo' essere scaricato da qui

lunedì 14 giugno 2021

Lock Picking

Avevo acquistato questo lucchetto e lo avevo messo alla bici...dopo qualche giorno ho perso le chiavi. Adesso devo vendere la bici e  volevo toglierlo ... ma sono pigro per usare un seghetto

Francamente non pensavo cosi' facile



giovedì 10 giugno 2021

Eclisse solare 10 giugno 2021 Firenze ore 12:03

Immagine da telefono su oculare dell'eclisse solare del 10 giugno 2021 da Firenze


Il filtro solare devo ammettere che funziona bene...peccato non essere riusciti a montare la camera astronomica sull'oculare

questa e' versione virtuale di Stellarium



venerdì 14 maggio 2021

Esp32 Page Tuner Elgato Clone

Visto il precedente post volevo fare qualcosa di ancora piu' semplice e meno costoso

Ho provato ad usare come controller una ESP32...la prima idea era quella di usare la libreria BleKeyboard con dei tasti fisici per i controlli ma alla fine avevo bisogno di un po' di saldature...volevo qualcosa di ancora piu' semplice...ho quindi usato i pin touch della Esp32 che necessitano solo del contatto di un dito per essere usati come interrutori






Nell'esempio i pin Touch4 e Touch5 sono associati al tasto spazio e Freccia a sinistra per abilitare la funzione Play e Rewind su Youtube e VLC

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

#include <BleKeyboard.h>
#define interval 1000

BleKeyboard bleKeyboard;
int threshold = 40;
bool touch4detected = false;
bool touch5detected = false;
long previousMills = 0; 
void gotTouch5(){ 
 if (millis()-previousMills > interval)
    {
    touch5detected = true;
    previousMills = millis();
    }
}
void gotTouch4(){ 
 if (millis()-previousMills > interval)
    {
    touch4detected = true;
    previousMills = millis();
    }
}
void setup() {
  bleKeyboard.begin();
  delay(1000);
  while (!bleKeyboard.isConnected()) {
    Serial.println("in attesa");
  }
  
  Serial.begin(115200);
  delay(1000);
  
  touchAttachInterrupt(T4, gotTouch4, threshold);
  touchAttachInterrupt(T5, gotTouch5, threshold);
}
void loop(){
if(touch4detected){
  touch4detected = false;
  Serial.println("Play"); 
  bleKeyboard.print(" ");
  }
if(touch5detected){
  touch5detected = false;
  Serial.println("Rewind"); 
  bleKeyboard.write(KEY_LEFT_ARROW );
  }
}

venerdì 7 maggio 2021

Soliflusso

Un esempio di soliflusso nei prati della Consuma. 



Elgato controller clone

Per automatizzare Audacity mentre cerco di registrare la chitarra stavo pensando di costruirmi con Arduino una consolle di controllo tipo quello di Elgato quando mi e' venuta in mente una soluzione piu' semplice: utilizzare un controller midi per interagire con Audacity tramite xdotool , un software che simula l'interazione utente con una applicazione X e tramite la libreria Python https://pypi.org/project/python-rtmidi/



In estrema sintesi da rtmidi si riceve un codice del tasto midi premuto sul controller e con xdotool si invia la corrispondente sequenza di caratteri per generare un evento di Audacity

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

import sys
import rtmidi
import threading
import os

def print_message(midi, port):
    if midi.isNoteOn():
        #print '%s: ON: ' % port, midi.getMidiNoteName(midi.getNoteNumber()), midi.getVelocity()
        print midi.getNoteNumber() 
        if (midi.getNoteNumber() == 60):
        print "Play/Stop"
        os.system("xdotool search --onlyvisible --class 'Audacity' windowfocus key 'space'")
        if (midi.getNoteNumber() == 61):
        print "Play/Stop Cursor"
        os.system("xdotool search --onlyvisible --class 'Audacity' windowfocus key 'x'")
        if (midi.getNoteNumber() == 62):
        print "Track start"
        os.system("xdotool search --onlyvisible --class 'Audacity' windowfocus key 'J'")
       
        if (midi.getNoteNumber() == 64):
        print "Record"
        os.system("xdotool search --onlyvisible --class 'Audacity' windowfocus key 'shift+R'")
        if (midi.getNoteNumber() == 65):
        print "Pause"
        os.system("xdotool search --onlyvisible --class 'Audacity' windowfocus key 'p'")
class Collector(threading.Thread):
    def __init__(self, device, port):
        threading.Thread.__init__(self)
        self.setDaemon(True)
        self.port = port
        self.portName = device.getPortName(port)
        self.device = device
        self.quit = False
    def run(self):
        self.device.openPort(self.port)
        self.device.ignoreTypes(True, False, True)
        while True:
            if self.quit:
                return
            msg = self.device.getMessage()
            if msg:
                print_message(msg, self.portName)

dev = rtmidi.RtMidiIn()
collectors = []
for i in range(dev.getPortCount()):
    device = rtmidi.RtMidiIn()
    print 'OPENING',dev.getPortName(i)
    collector = Collector(device, i)
    collector.start()
    collectors.append(collector)

print 'HIT ENTER TO EXIT'
sys.stdin.read(1)
for c in collectors:
    c.quit = True


martedì 20 aprile 2021

martedì 30 marzo 2021

Certificato Codemotion Online Tech Conference 2021 - Italian Edition

 



Lettore file UBX in Python

uno script scritto di fretta per risolvere un problema di debug sulla trasmissione via radio di un file ubx 

magari puo' servire a qualcun altro

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

def crc_check(valore):

global ck_a

global ck_b

ck_a = (ck_a+valore) % 256

ck_b = (ck_b+ck_a) % 256

#print "CK_A : " + str(hex(ck_a)) + "  CK_B : " + str(hex(ck_b))


#file = open('acm0_remoto.ubx', 'r')

#file = open('usb0.ubx', 'r')

file = open('arcetri_ucenter.ubx', 'r')

#file = open('orto.ubx', 'r')

off=0

fine=0

ck_a = 0

ck_b = 0


good = 0

bad = 0


pacchetto = -1

while 1:

char = file.read(1)

off=off+1

pacchetto = ""

if ord(char) == 181: #B5

pacchetto = pacchetto + char

if (off == (fine+1)):

print "OK"

inizio = off -1

ck_a = 0

ck_b = 0

char = file.read(1)

off=off+1

#pacchetto = pacchetto + char

if ord(char) == 98: #62

#

if (inizio == fine + 1):

print "////////////////////// OK ////////////////"

print "/////////////////// " + hex(lungh) +" ////////////////"

#good = good + 1

else:

print "******************** ERRORE **************"

print "*****************DIFF " + hex(inizio-fine) + "*********"

#somma_diff = somma_diff + (inizio-fine)

#bad = bad+1

print "================================================="

print "======GOOD :" + str(good) + "==========BAD :"+ str(bad) + "==========================="

print "================================================="

pacchetto = pacchetto + char

print "Offset inizio: " + hex(inizio)

char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print "Message Class: " + hex(ord(char)),

if (ord(char) == 1):

print " NAV ",

if (ord(char) == 2):

print " RXM ",

if (ord(char) == 4):

print " INF ",

if (ord(char) == 5):

print " ACK ",

if (ord(char) == 6):

print " CFG ",

if (ord(char) == 10):

print " MON ",

if (ord(char) == 11):

print " AID ",

if (ord(char) == 13):

print " TIM ",

classe = ord(char)

crc_check(ord(char))

char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print " Message ID: " + hex(ord(char)),

crc_check(ord(char))

if (classe == 2):

if (ord(char)) == 0x10:

print " RAW "

if (ord(char)) == 0x11:

print " SFRB "

if (ord(char)) == 0x12:

print " SFRBX "

if (ord(char)) == 0x13:

print " RAWX "

print 

char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print "Payload Length High: " + hex(ord(char))# + " " + str(ord(char))

lungh = ord(char)

crc_check(ord(char))

char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print "Payload Length Low: "  + hex(ord(char))# + " " + str(ord(char))

lungh = (256*ord(char)) + lungh

print "Lunghezza :" + str(hex(lungh))#+ " " + str(lungh)

crc_check(ord(char))

for t in range(lungh):

char = file.read(1)

print hex(ord(char)),

pacchetto = pacchetto + char

off=off+1

crc_check(ord(char))

print 

char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print 

crc_1 = ord(char)


char = file.read(1)

pacchetto = pacchetto + char

off=off+1

print "CRC 1: " + hex(crc_1) +"  CRC 2: " + hex(ord(char))

crc_2 = ord(char)

print "CK_A  :" + hex(ck_a) + "  CK_B : " + hex(ck_b)

if ((ck_a == crc_1) and (ck_b == crc_2)):

print "CRC OK"

good = good + 1

corretto = open('corretto.ubx', 'a')

corretto.write(pacchetto)

corretto.close()

else:

print "Errore CRC"

bad = bad + 1 


fine = off-1

print "Fine :" + hex(fine)

try:

input()

except SyntaxError:

pass

LLama3 Anita

A seguito di questo post ho provato a vedere ho provato a vedere cosa accadeva ad utilizzare un modello specifico per la lingua italiana in...