Visualizzazione post con etichetta Paleontologia. Mostra tutti i post
Visualizzazione post con etichetta Paleontologia. Mostra tutti i post

martedì 26 novembre 2019

Classificazione binaria foraminferi con Tensorflow

Per continuare gli esperimenti questa una classificazione binaria con Tensorflow.
Le due categorie sono riprese dal precedente post (1500 elementi)


Globigerinoides Ruber
Globigerina Bulloides

train
======================================================
import os


a_dir = os.path.join('./train/globigerinoides_ruber')
b_dir = os.path.join('./train/globigerina_bulloides')


print('globigerinoides_ruber images:', len(os.listdir(a_dir)))
print('globigerina_bulloides images:', len(os.listdir(b_dir)))

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

batch_size = 16


from tensorflow.keras.preprocessing.image import ImageDataGenerator
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Conv2D, Flatten, Dropout, MaxPooling2D
from tensorflow.keras.preprocessing.image import ImageDataGenerator

train_datagen = ImageDataGenerator(rescale=1/255)

train_generator = train_datagen.flow_from_directory(
        './train_binary',  
        target_size=(200, 200),  
        batch_size=batch_size,
shuffle=True,
        class_mode='binary')

import tensorflow as tf

model = Sequential([
    Conv2D(16, 3, padding='same', activation='relu', input_shape=(200, 200 ,3)),
    MaxPooling2D(),
    Conv2D(32, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Conv2D(64, 3, padding='same', activation='relu'),
    MaxPooling2D(),
    Flatten(),
    Dense(512, activation='relu'),
    Dense(1, activation='sigmoid')
])

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


model.summary()

total_sample=train_generator.n

n_epochs = 15
history = model.fit_generator(
        train_generator, 
        steps_per_epoch=int(total_sample/batch_size),  
        epochs=n_epochs,
        verbose=1)

model.save('1500el_5classi_binary_model.h5')

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

predict
======================================================
import tensorflow as tf
from tensorflow.keras import Model 
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import sys
from numpy import asarray
import numpy as np

model = tf.compat.v2.keras.models.load_model('1500el_5classi_binary_model.h5')



image = Image.open(sys.argv[1])
image = image.resize((200,200))
pic = asarray(image)
pic = pic.astype('float32')
pic /= 255.0

pic=np.expand_dims(pic,axis=0)


prediction = model.predict(pic)
print(sys.argv[1])

float_formatter = "{:.2f}".format
np.set_printoptions(formatter={'float_kind':float_formatter})
print(prediction)


print()
======================================================

I risultati indicano 19 tentativi 13 corrette identificazioni (69%), 2 casi incerti (10.5%), 2 errori  (10.5%)


Globigerinoides Ruber Globigerina Bulloides


Predizione
Immagini reali



Globigerina Bulloides 1 0% 100%

2 100% 0%

3 0% 100%

4 0% 100%

5 0% 100%

6 58% 42%

7 47% 53%

8 0% 100%

9 0% 100%
Globigerinoides Ruber 1 100% 0%

2 0% 100%

3 63% 37%

4 100% 0%

5 100% 0%

6 94% 6%

7 0% 100%

8 0% 100%

9 100% 0%

10 100% 0%

venerdì 22 novembre 2019

Riconoscimento foraminiferi con rete neurale Tensorflow

Questa versione di codice prevede l'uso completo di Tensorflow Keras per creare delle classificazioni di immagini per il riconoscimento di foraminiferi(il codice e' stato adattato dal seguente link).
Spoiler: il modello ha effettuato il corretto riconoscimento di poco oltre il 54% dei tentativi...tirando a caso i successi stimati sarebbero del 20%


il dataaset non e' enorme ma si tratta di un esempio (immagini tratte da http://www.endlessforams.org/)

Sono state selezionate le specie con almeno 1500 immagini (ogni classe ha lo stesso numero di immagini in modo da non favorire nessuna classe nel training) e sono state selezionate le immagini a piu' alta qualita'

globigerinoides_ruber images: 1500
globigerina_bulloides images: 1500
globigerinita_glutinata images: 1500
globigerinoides_sacculifer images: 1500
neogloboquadrina_pachyderma images: 1500

le immagini dei foraminiferi sono classificate all'interno delle cartelle con il nome della rispettiva specie. Per questo esempio sono state selezionate 5 specie e quindi 5 classi
Si tratta quindi di algoritmi di image classification basati su class_mode=categorical

le immagini originali sono state tagliate dei 160 pixel alla base per togliere la banda bianca con le scritte
-------------------------------------------
for f in *.jpg
do
convert $f -gravity South -chop 0x160 a_$f
done
-------------------------------------------


===========================================================
import os


a_dir = os.path.join('./train/globigerinoides_ruber')
b_dir = os.path.join('./train/globigerina_bulloides')
c_dir = os.path.join('./train/globigerinita_glutinata')
d_dir = os.path.join('./train/globigerinoides_sacculifer')
e_dir = os.path.join('./train/neogloboquadrina_pachyderma')


print('globigerinoides_ruber images:', len(os.listdir(a_dir)))
print('globigerina_bulloides images:', len(os.listdir(b_dir)))
print('globigerinita_glutinata images:', len(os.listdir(c_dir)))
print('globigerinoides_sacculifer images:', len(os.listdir(d_dir)))
print('neogloboquadrina_pachyderma images:', len(os.listdir(e_dir)))

import matplotlib.pyplot as plt
import matplotlib.image as mpimg

batch_size = 16

from tensorflow.keras.preprocessing.image import ImageDataGenerator

# riscala i valorei
train_datagen = ImageDataGenerator(rescale=1/255)

train_generator = train_datagen.flow_from_directory(
        './train',  
        target_size=(200, 200),  # tutte le immagini vengono riscalate a 200x200. Gli originali sono circa 400x640
        batch_size=batch_size,
        classes = ['globigerinoides_ruber','globigerina_bulloides','globigerinita_glutinata','globigerinoides_sacculifer','neogloboquadrina_pachyderma'],
        class_mode='categorical')

import tensorflow as tf


model = tf.keras.models.Sequential([
    # The first convolution
    tf.keras.layers.Conv2D(16, (3,3), activation='relu', input_shape=(200, 200, 3)),
    tf.keras.layers.MaxPooling2D(2, 2),
    tf.keras.layers.Conv2D(32, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Conv2D(64, (3,3), activation='relu'),
    tf.keras.layers.MaxPooling2D(2,2),
    tf.keras.layers.Flatten(),
    tf.keras.layers.Dense(128, activation='relu'),
    # softmax deve essere impostato al numero di classi 
    tf.keras.layers.Dense(5, activation='softmax')
])

model.summary()

from tensorflow.keras.optimizers import RMSprop

model.compile(loss='categorical_crossentropy',
              optimizer=RMSprop(lr=0.001),
              metrics=['acc'])

total_sample=train_generator.n

n_epochs = 15
history = model.fit_generator(
        train_generator, 
        steps_per_epoch=int(total_sample/batch_size),  
        epochs=n_epochs,
        verbose=1)

model.save('1500el_5classi_model.h5')

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

i dati sono salvati in un file .h5

per la verifica del modello sono state selezionate 5 immagini per ogni classe che non erano comprese nel training con 15 epochs
questo e' lo script di predizione basato sulla libreria creata in precedenza (il nome del file immagine da esaminare viene passato sulla linea di comando)
============================================================
import tensorflow as tf
from tensorflow.keras import Model 
from PIL import Image
import matplotlib.pyplot as plt
import matplotlib.image as mpimg
import sys
from numpy import asarray
import numpy as np

model = tf.compat.v2.keras.models.load_model('../1500el_5classi_model.h5')

image = Image.open(sys.argv[1])
image = image.resize((200,200))
pic = asarray(image)
pic = pic.astype('float32')
pic /= 255.0

pic=np.expand_dims(pic,axis=0)


prediction = model.predict(pic)
print(sys.argv[1])

float_formatter = "{:.2f}".format
np.set_printoptions(formatter={'float_kind':float_formatter})
print(prediction)
print()
============================================================


i risulati sono i seguenti





Corretti Errati
Globigerina Bulloides

9 1
Globigerinita Glutinata

1 9
Globigerinoides Ruber

3 7
Globigerinoides Sacculifer

9 0
Neogloboquadrina Pachyderma

3 6








52% 48%


I risultati delle colonne seguenti sono in percentuali di affidabilita' (1=100%)



Globigerinoides Ruber Globigerina Bulloides Globigerinita Glutinata Globigerinoides Sacculifer Neogloboquadrina Pachyderma


Predizione
Immagini reali






Globigerina Bulloides 1
1.00




2
1.00




3
1.00




4
1.00




5
1.00




6
0.17
0.93


7 0.25 0.74
0.01


8
1.00




9
1.00




10
1.00



Globigerinita Glutinata 1
0.95
0.04


2 0.32 0.03
0.65


3 0.01 0.77 0.05 0.18


4
0.79 0.17 0.01 0.03

5 0.07 0.05 0.68 0.20


6 0.82 0.02 0.03 0.13


7
0.94 0.06



8 0.00 0.61 0.04 0.35


9 0.21 0.11 0.1 0.58


10 0.12 0.14 0.01 0.73

Globigerinoides Ruber 1

1.00



2 0.02 0.98




3 0.26 0.18
0.55


4

1.00



5 0.98 0.01
0.01


6 0.70

0.30


7 0.02

0.98


8

1.00


9


1.00


10 0.63

0.36

Globigerinoides Sacculifer 1 0.27

0.73


2
0.01
0.99


3


1.00


4


1.00


5
0.07
0.93


6


1.00


7


1.00


8


1.00


9


1.00

Neogloboquadrina Pachyderma 1

1.00


2


1.00


3


0.89 0.01

4 0.01

0.01 0.98

5


1.00


6



1.00

7


0.95 0.01

8 0.08

0.08 0.83

9
0.02
0.97




Aggiungedo un Dropout del 20% le cose migliorano ma non troppo






Corretti Errati
Globigerina Bulloides

10 0
Globigerinita Glutinata

4 6
Globigerinoides Ruber

5 5
Globigerinoides Sacculifer

6 3
Neogloboquadrina Pachyderma

1 9








54% 48%


ho provato ad usare l'optimizer adam con 3 livelli di convoluzione ma i risultati sono stati peggiori

martedì 19 novembre 2019

Riconoscimento foraminiferi con rete neurale Tensorflow Lite

Questo e' sempre stato uno dei miei sogni quando studiavo micropaleontologia....avere un sistema automatico (o semi automatico) che mi aiutasse nel riconoscimento di foraminiferi (planctonici del Miocene nel caso specifico)



Con Tensorflow Lite si puo' arrivare a qualcosa di simile
Prima di iniziare pero e' necessario avere una buona base di immagini....in cio' viene in aiuto il sito
http://www.endlessforams.org/ da cui e' possibile scaricare le fotografie di foraminiferi gia' classificati

Nello specifico, per il mio test, ho selezionato le prime 100 foto delle specie

Globigerina Falconensis
Globigerina Bulloides
Globigerinella Calida
Globigerinella Siphonifera
Globorotalia Crassiformis
Orbulina Universa

alcune sono state scelte volutamente con morfologia simile in modo da vedere il grado di risoluzione della macchina neurale. Queste 600 immagini sono in train dataset mentre sono state selezionate ulteriore 12 immagini (2 per specie) come test dataset; le immagini di test ovviamente non sono incluse nel set di apprendimento

Le immagini sono organizzate in una struttura di directory come in immagine seguente

In pratica il nome della directory e' la label utilizzata da Tensorflow per image recognition

E' giunto il momento di creare la libreria personalizzata di Tensorflow con il seguente script Python

Si apre il virtual environment con venv/bin/activate e si lancia

====================================================
from __future__ import absolute_import, division, print_function, unicode_literals

import numpy as np

import tensorflow as tf
assert tf.__version__.startswith('2')

from tensorflow_examples.lite.model_customization.core.data_util.image_dataloader import ImageClassifierDataLoader
from tensorflow_examples.lite.model_customization.core.task import image_classifier
from tensorflow_examples.lite.model_customization.core.task.model_spec import efficientnet_b0_spec
from tensorflow_examples.lite.model_customization.core.task.model_spec import ImageModelSpec

import matplotlib.pyplot as plt

image_path = "./foraminifera/"

data = ImageClassifierDataLoader.from_folder(image_path)
model = image_classifier.create(data)
loss, accuracy = model.evaluate()
model.export('fora_classifier.tflite', 'fora_labels.txt')
====================================================

a questo punto si e' pronti per testare la libreria con il seguente script
====================================================
"""label_image for tflite."""

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import argparse
import numpy as np

from PIL import Image

#import tensorflow as tf # TF2
import tflite_runtime.interpreter as tflite



def load_labels(filename):
  with open(filename, 'r') as f:
    return [line.strip() for line in f.readlines()]


if __name__ == '__main__':
  parser = argparse.ArgumentParser()
  parser.add_argument(
      '-i',
      '--image',
      default='./test_image/orbulina_test.jpg',
      help='image to be classified')
  parser.add_argument(
      '-m',
      '--model_file',
      default='fora_classifier.tflite',
      help='.tflite model to be executed')
  parser.add_argument(
      '-l',
      '--label_file',
      default='fora_labels.txt',
      help='name of file containing labels')
  parser.add_argument(
      '--input_mean',
      default=127.5, type=float,
      help='input_mean')
  parser.add_argument(
      '--input_std',
      default=127.5, type=float,
      help='input standard deviation')
  args = parser.parse_args()

  #interpreter = tf.lite.Interpreter(model_path=args.model_file)

  interpreter = tflite.Interpreter(model_path=args.model_file)

  interpreter.allocate_tensors()

  input_details = interpreter.get_input_details()
  output_details = interpreter.get_output_details()

  # check the type of the input tensor
  floating_model = input_details[0]['dtype'] == np.float32

  # NxHxWxC, H:1, W:2
  height = input_details[0]['shape'][1]
  width = input_details[0]['shape'][2]
  img = Image.open(args.image).resize((width, height))

  # add N dim
  input_data = np.expand_dims(img, axis=0)

  if floating_model:
    input_data = (np.float32(input_data) - args.input_mean) / args.input_std

  interpreter.set_tensor(input_details[0]['index'], input_data)

  interpreter.invoke()

  output_data = interpreter.get_tensor(output_details[0]['index'])
  results = np.squeeze(output_data)

  top_k = results.argsort()[-5:][::-1]
  labels = load_labels(args.label_file)
  for i in top_k:
    if floating_model:
      print('{:08.6f}: {}'.format(float(results[i]), labels[i]))
    else:
      print('{:08.6f}: {}'.format(float(results[i] / 255.0), labels[i]))
====================================================

lo script si lancia con la sintassi

(venv) luca@debian:~/tensor/tf_spectra/fora$ python classify_image_2.py -i ./test_image/crassaformis_test.jpg

in pratica con lo switch -i si indica il file immagine di test di cui si vuole riconoscere l'immagine

un risultato di esempio e'

(venv) luca@debian:~/tensor/tf_spectra/fora$ python classify_image_2.py -i ./test_image/crassaformis_test.jpg
INFO: Initialized TensorFlow Lite runtime.
0.823927: globorotalia_crassaformis
0.098882: globigerina_bulloides
0.031008: globigerinella_calida
0.023761: globiferina_falconensis
0.015816: orbulina_universa

in pratica l'immagine di test di una Globorotalia Crassaformis e' stato riconosciuta al 83% di confidenza con la giusta classificazione
Mettendo in tabella i risultati


In verde la corretta attribuzione, in arancione attribuzione errata da parte della rete neurale

commentando i risultati si osserva che su 12 test 8 hanno portato ad un corretto riconoscimento, con punteggi molto alti in caso di foraminiferi molto caratteristici come le Orbuline, in un caso e' stato individuato in modo corretto il genere ma non la specie, mentre nei due rimanenti casi di errata classificazione l'errore e' molto marcato

1. Hsiang AY, Brombacher A, Rillo MC, Mleneck-Vautravers MJ, Conn S, Lordsmith S, Jentzen A, Henehan MJ, Metcalfe B, Fenton I, Wade BS, Fox L, Meilland J, Davis CV, Baranowski U, Groeneveld J, Edgar KM, Movellan A, Aze T, Dowsett H, Miller G, Rios N, Hull PM. (2019) Endless Forams: >34,000 modern planktonic foraminiferal images for taxonomic training and automated species recognition using convolutional neural networks. Paleoceanography & Paleoclimatology, 34. https://doi.org/10.1029/2019PA003612
2. Elder L.E., Hsiang A.Y., Nelson K., Strotz L.C., Kahanamoku S.S., Hull P.M. Sixty-one thousand recent planktonic foraminifera from the Atlantic Ocean. Scientific Data 5: 180109. https://doi.org/10.1038/sdata.2018.109
3. Rillo M.C., Whittaker J., Ezard T.H.G., Purvis A., Henderson A.S., Stukins S., Miller C.G. 2016. The unknown planktonic foraminiferal pioneer Henry Buckley and his collection at The Natural History Museum, London. Journal of Micropalaeontology. https://doi.org/10.1144/jmpaleo2016-020

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...