Data Understanding - Health Check
Contents
Data Understanding - Health Check#
In diesen Notebook werden die Merkmale Train-Test-Split, Instanzen/Bilder pro Klasse und Bildergröße der genutzten Daten des DOTA-Data Sets untersucht.
import plotly.io as pio
import os
import re
from PIL import Image
pio.templates.default = "plotly_white"
import plotly.graph_objects as go
import plotly.express as px
import pandas as pd
import numpy as np
from plotly.offline import init_notebook_mode
from google.colab import drive
drive.mount('/content/drive')
Mounted at /content/drive
def configure_plotly_browser_state():
import IPython
display(IPython.core.display.HTML('''
<script src="/static/components/requirejs/require.js"></script>
<script>
requirejs.config({
paths: {
base: '/static/base',
plotly: 'https://cdn.plot.ly/plotly-latest.min.js?noext',
},
});
</script>
'''))
Train-Test-Split#
Beim Train-Test-Split wird das Verhältnis zwischen Trainings- und Validierungsdaten untersucht. Zu berücksichtigen ist hierbei, dass der Datensatz bereits einen Split vorgibt, da Trainings- und Validierungsdaten in verschiedenenen Ordnern hochgeladen sind.
myPathLabeltrain = '/content/drive/MyDrive/dataset/labels/train/'
myPathLabelval = '/content/drive/MyDrive/dataset/labels/validation/'
myPathImagestrain = '/content/drive/MyDrive/dataset/images/removed_background_train/'
myPathImagesval = '/content/drive/MyDrive/dataset/images/removed_background_validation/'
no_background_train = len(os.listdir(myPathLabeltrain))
no_background_val = len(os.listdir(myPathLabelval))
print(f"Anzahl Trainingsbilder ohne Hintergrundbilder: {no_background_train} \nAnzahl Testbilder ohne Hintergrundbilder: {no_background_val} \n")
print(f"Ergeben einen Split von {round(no_background_val/(no_background_train+no_background_val),2)*100} % Testdaten")
Anzahl Trainingsbilder ohne Hintergrundbilder: 197
Anzahl Testbilder ohne Hintergrundbilder: 70
Ergeben einen Split von 26.0 % Testdaten
Durch die Filterung der Daten auf Flugzeuge und Helikopter wird eine Verschiebung des Train-Test-Splits vermutet. Die Differenz zu den ursprünglichen 24,4% ist jedoch minimal. [Xia et al., 2018]
background_train = len(os.listdir(myPathImagestrain))
background_val = len(os.listdir(myPathImagesval))
print(f"Anzahl Trainingsbilder mit Hintergrundbilder: {background_train} \nAnzahl Testbilder mit Hintergrundbilder: {background_val} \n")
print(f"Ergeben einen Split von {round(background_val/(background_train+background_val),2)*100} % Testdaten")
Anzahl Trainingsbilder mit Hintergrundbilder: 620
Anzahl Testbilder mit Hintergrundbilder: 458
Ergeben einen Split von 42.0 % Testdaten
Nach der Empfehlung aus Dokumentation von YOLOv5 wurden zu den gefilterten Daten in zwei Schritten Hintergrundbilder aus dem Dota-Trainingssatz hinzugefügt, welche keine Flugzeuge und Helikopter enthalten. Nach dem Einfügen der Background-Bilder wurde der Train-Test-Split nicht nochmal überprüft. Dies führt zu einer Verschiebung. In einer weiterführenden Arbeit sollte dies optimiert werden.
Instanzen pro Klasse#
Für optimale Trainingsergebnisse wird in der Dokumentation von YOLOv5 10.000 Instanzen pro Klasse empfohlen [Jocher, 2022]. Dies wird im Folgenden untersucht.
all_labels_train = os.listdir(myPathLabeltrain)
number_heli = 0
number_planes = 0
number_images_heli = 0
number_images_plane = 0
for file in all_labels_train:
heli = False
plane = False
path = myPathLabeltrain + file
with open(path) as f:
for line in f:
if (re.match("^0", line)):
number_planes = number_planes +1
plane = True
elif (re.match("^1", line)):
number_heli = number_heli +1
heli = True
if plane == True:
number_images_plane = number_images_plane +1
if heli == True:
number_images_heli = number_images_heli + 1
configure_plotly_browser_state()
init_notebook_mode(False) # To show plotly plots when notebook is exported to html
instances=['planes', 'helicopter']
fig = go.Figure([go.Bar(x=instances, y=[number_planes, number_heli])])
fig.show()
Fig. 26 Eigene Darstellung: Barplot Anzahl an Instanzen nach Label#
Beide Klassen erreichen nicht den erforderlichen Wert. Wobei die Klasse Helikopter mit 601 Instanzen ein deutlich zu geringe Anzahl aufweist.
Bilder pro Klasse#
Ähnlich wie bei den Instanzen enthält die YOLOv5-Dokumentation auch eine Empfehlung zu der Anzahl von Bildern pro Klasse. Diese liegt bei 1500.
instances=['images planes', 'images helicopter']
configure_plotly_browser_state()
init_notebook_mode(False) # To show plotly plots when notebook is exported to html
fig = go.Figure([go.Bar(x=instances, y=[number_images_plane, number_images_heli])])
fig.show()
Fig. 27 Eigene Darstellung: Barplot Anzahl an Bildern nach Label#
Auch bei Bildern pro Klasse liegen beide Klassen unter den Empfehlungen.
Bildgröße und Proportionen#
Wie bereits im Abschnitt zu den Tarnkappenbomber erläutert, ist die optimale Auflösung für YOLOv5 640x640 Pixel. Aus diesem Grund wird in diesem Abschnitt die Bildgröße und die Bildproportionen untersucht.
all_images_train = os.listdir(myPathImagestrain)
def get_num_pixels(filepath):
width, height = Image.open(filepath).size
return width, height
width_size = list()
height_size = list()
size_cat = list()
for file in all_images_train:
path = myPathImagestrain + file
width, height = get_num_pixels(path)
if (width <= 640 and height <= 640):
size_cat.append('opt')
elif (width <= 1280 and height <= 1280):
size_cat.append('big')
else:
size_cat.append('very big')
width_size.append(width)
height_size.append(height)
print(np.median(width_size))
print(np.median(height_size))
1486.0
1372.0
df = pd.DataFrame(dict(
x = width_size,
y = height_size,
cat= size_cat
))
configure_plotly_browser_state()
init_notebook_mode(False) # To show plotly plots when notebook is exported to html
fig = px.scatter(df, x="x", y="y", color = "cat")
fig.update_layout(
shapes=[
dict(
type= 'line',
yref= 'y', y0=0, y1= 12000,
xref= 'x', x0=0, x1= 12000
)])
fig.add_vline(x=1280, line_width=1.5, line_dash="dash", line_color='#388A73',row=1,col=1)
fig.add_hline(y=1280, line_width=1.5, line_dash="dash", line_color='#388A73',row=1,col=1)
fig.show()
Fig. 28 Eigene Darstellung: Bildgröße nach Pixeln#
Die Bildproportionen sind größtenteils nicht quadratisch und werden aus diesem Grund verzerrt. Ebenfalls sind nur drei Bilder kleiner als 640 Pixel. Darüber hinaus liegen ein Großteil der Bilder auch über der Empfehlung für “small objects” mit 1280 Pixel, wie die obere Grafik zeigt. Dies muss in der Modellerstellung berücksichtigt werden.