Künstliche Intelligenz versus Lüge und Betrug

Bei allen Aufgaben des Lehrens künstlicher Intelligenz gibt es ein unangenehmes Phänomen - Fehler im Markup der Trainingssequenz. Diese Fehler sind unvermeidlich, da das gesamte Markup manuell erfolgt. Wenn es eine Möglichkeit gibt, echte Daten programmgesteuert zu markieren, warum brauchen wir dann jemanden, der ihnen das Markieren beibringt und Zeit und Geld für die Erstellung eines absolut unnötigen Designs aufwendet?

Das Auffinden und Entfernen gefälschter Masken in einer großen Trainingssequenz ist ziemlich kompliziert. Sie können sie alle manuell anzeigen, dies erspart Ihnen jedoch keine wiederholten Fehler. Wenn Sie sich jedoch die in früheren Beiträgen vorgeschlagenen Tools zum Studium neuronaler Netze genau ansehen, stellt sich heraus, dass es eine einfache und effektive Möglichkeit gibt, alle Artefakte aus der Trainingssequenz zu erkennen und zu extrahieren.

Und in diesem Beitrag gibt es ein konkretes Beispiel, es ist offensichtlich, dass ein einfaches Beispiel auf Ellipsen und Polygonen für ein gewöhnliches U-Netz wieder ein solches Lego im Sandkasten ist, aber ungewöhnlich konkret, nützlich und effektiv. Wir werden zeigen, wie eine einfache Methode fast alle Artefakte identifiziert und findet, alle Lügen der Trainingssequenz.

Also fangen wir an!

Nach wie vor werden wir die Reihenfolge der Bild / Masken-Paare untersuchen. In dem zufällig ausgewählten Bild in verschiedenen Vierteln platzieren wir eine Ellipse einer zufälligen Größe und ein Viereck einer beliebigen Größe, und beide Farben in derselben Farbe, ebenfalls zufällig ausgewählt aus zwei von ihnen. In der zweiten verbleibenden Farbe färben wir den Hintergrund. Die Abmessungen sowohl der Ellipse als auch des Vierecks sind natürlich begrenzt.

In diesem Fall werden wir jedoch Änderungen in das Paargenerierungsprogramm einführen und zusammen mit einer vollständig korrekten Maske eine falsche, durch eine Lüge vergiftete Maske vorbereiten. In etwa einem Prozent der Fälle ersetzen Sie das Viereck in der Maske durch eine Ellipse, d. H. Das wahre Objekt für die Segmentierung wird durch falsche Masken als Ellipse und nicht als Viereck bezeichnet.

Zufällige Beispiele 10



Beispiele für zufällige 10, aber von fehlerhaften Markups. Die obere Maske ist wahr, die untere ist falsch und die Zahlen in der Trainingssequenz sind in den Bildern gezeigt.



Für die Segmentierung verwenden wir dieselben Metrik- und Verlustberechnungsprogramme und dasselbe einfache U-Netz, verwenden jedoch kein Dropout.

Bibliotheken
import numpy as np import matplotlib.pyplot as plt from matplotlib.colors import NoNorm %matplotlib inline import math from tqdm import tqdm #from joblib import Parallel, delayed from skimage.draw import ellipse, polygon from keras import Model from keras.optimizers import Adam from keras.layers import Input,Conv2D,Conv2DTranspose,MaxPooling2D,concatenate from keras.layers import BatchNormalization,Activation,Add,Dropout from keras.losses import binary_crossentropy from keras import backend as K from keras.models import load_model import tensorflow as tf import keras as keras w_size = 128 train_num = 10000 radius_min = 10 radius_max = 30 


Metrik- und Verlustfunktionen
 def dice_coef(y_true, y_pred): y_true_f = K.flatten(y_true) y_pred = K.cast(y_pred, 'float32') y_pred_f = K.cast(K.greater(K.flatten(y_pred), 0.5), 'float32') intersection = y_true_f * y_pred_f score = 2. * K.sum(intersection) / (K.sum(y_true_f) + K.sum(y_pred_f)) return score def dice_loss(y_true, y_pred): smooth = 1. y_true_f = K.flatten(y_true) y_pred_f = K.flatten(y_pred) intersection = y_true_f * y_pred_f score = (2. * K.sum(intersection) + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth) return 1. - score def bce_dice_loss(y_true, y_pred): return binary_crossentropy(y_true, y_pred) + dice_loss(y_true, y_pred) def get_iou_vector(A, B): # Numpy version batch_size = A.shape[0] metric = 0.0 for batch in range(batch_size): t, p = A[batch], B[batch] true = np.sum(t) pred = np.sum(p) # deal with empty mask first if true == 0: metric += (pred == 0) continue # non empty mask case. Union is never empty # hence it is safe to divide by its number of pixels intersection = np.sum(t * p) union = true + pred - intersection iou = intersection / union # iou metrric is a stepwise approximation of the real iou over 0.5 iou = np.floor(max(0, (iou - 0.45)*20)) / 10 metric += iou # teake the average over all images in batch metric /= batch_size return metric def my_iou_metric(label, pred): # Tensorflow version return tf.py_func(get_iou_vector, [label, pred > 0.5], tf.float64) from keras.utils.generic_utils import get_custom_objects get_custom_objects().update({'bce_dice_loss': bce_dice_loss }) get_custom_objects().update({'dice_loss': dice_loss }) get_custom_objects().update({'dice_coef': dice_coef }) get_custom_objects().update({'my_iou_metric': my_iou_metric }) 


Normales U-Netz
 def build_model(input_layer, start_neurons): # 128 -> 64 conv1 = Conv2D(start_neurons * 1, (3, 3), activation="relu", padding="same")(input_layer) conv1 = Conv2D(start_neurons * 1, (3, 3), activation="relu", padding="same")(conv1) pool1 = Conv2D(start_neurons * 1, (2, 2), strides=(2, 2), activation="relu", padding="same")(conv1) # pool1 = Dropout(0.25)(pool1) # 64 -> 32 conv2 = Conv2D(start_neurons * 2, (3, 3), activation="relu", padding="same")(pool1) conv2 = Conv2D(start_neurons * 2, (3, 3), activation="relu", padding="same")(conv2) pool2 = Conv2D(start_neurons * 1, (2, 2), strides=(2, 2), activation="relu", padding="same")(conv2) # pool2 = Dropout(0.5)(pool2) # 32 -> 16 conv3 = Conv2D(start_neurons * 4, (3, 3), activation="relu", padding="same")(pool2) conv3 = Conv2D(start_neurons * 4, (3, 3), activation="relu", padding="same")(conv3) pool3 = Conv2D(start_neurons * 1, (2, 2), strides=(2, 2), activation="relu", padding="same")(conv3) # pool3 = Dropout(0.5)(pool3) # 16 -> 8 conv4 = Conv2D(start_neurons * 8, (3, 3), activation="relu", padding="same")(pool3) conv4 = Conv2D(start_neurons * 8, (3, 3), activation="relu", padding="same")(conv4) pool4 = Conv2D(start_neurons * 1, (2, 2), strides=(2, 2), activation="relu", padding="same")(conv4) # pool4 = Dropout(0.5)(pool4) # Middle convm = Conv2D(start_neurons * 16, (3, 3), activation="relu", padding="same")(pool4) convm = Conv2D(start_neurons * 16, (3, 3) , activation="relu", padding="same")(convm) # 8 -> 16 deconv4 = Conv2DTranspose(start_neurons * 8, (3, 3), strides=(2, 2), padding="same")(convm) uconv4 = concatenate([deconv4, conv4]) # uconv4 = Dropout(0.5)(uconv4) uconv4 = Conv2D(start_neurons * 8, (3, 3) , activation="relu", padding="same")(uconv4) uconv4 = Conv2D(start_neurons * 8, (3, 3) , activation="relu", padding="same")(uconv4) # 16 -> 32 deconv3 = Conv2DTranspose(start_neurons * 4, (3, 3), strides=(2, 2), padding="same")(uconv4) uconv3 = concatenate([deconv3, conv3]) # uconv3 = Dropout(0.5)(uconv3) uconv3 = Conv2D(start_neurons * 4, (3, 3) , activation="relu", padding="same")(uconv3) uconv3 = Conv2D(start_neurons * 4, (3, 3) , activation="relu", padding="same")(uconv3) # 32 -> 64 deconv2 = Conv2DTranspose(start_neurons * 2, (3, 3), strides=(2, 2), padding="same")(uconv3) uconv2 = concatenate([deconv2, conv2]) # uconv2 = Dropout(0.5)(uconv2) uconv2 = Conv2D(start_neurons * 2, (3, 3) , activation="relu", padding="same")(uconv2) uconv2 = Conv2D(start_neurons * 2, (3, 3) , activation="relu", padding="same")(uconv2) # 64 -> 128 deconv1 = Conv2DTranspose(start_neurons * 1, (3, 3), strides=(2, 2), padding="same")(uconv2) uconv1 = concatenate([deconv1, conv1]) # uconv1 = Dropout(0.5)(uconv1) uconv1 = Conv2D(start_neurons * 1, (3, 3) , activation="relu", padding="same")(uconv1) uconv1 = Conv2D(start_neurons * 1, (3, 3) , activation="relu", padding="same")(uconv1) # uncov1 = Dropout(0.5)(uconv1) output_layer = Conv2D(1, (1,1), padding="same", activation="sigmoid")(uconv1) return output_layer input_layer = Input((w_size, w_size, 1)) output_layer = build_model(input_layer, 27) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-4), metrics=[my_iou_metric]) model.summary() 


Das Programm zum Generieren von Bildern und Masken - wahr und falsch. Die erste Ebene des Bildes wird in das Array eingefügt, die zweite ist die wahre Maske und die dritte Ebene ist die falsche Maske.

 def next_pair_f(idx): img_l = np.ones((w_size, w_size, 1), dtype='float')*0.45 img_h = np.ones((w_size, w_size, 1), dtype='float')*0.55 img = np.zeros((w_size, w_size, 3), dtype='float') i0_qua = math.trunc(np.random.sample()*4.) i1_qua = math.trunc(np.random.sample()*4.) while i0_qua == i1_qua: i1_qua = math.trunc(np.random.sample()*4.) _qua = np.int(w_size/4) qua = np.array([[_qua,_qua],[_qua,_qua*3],[_qua*3,_qua*3],[_qua*3,_qua]]) p = np.random.sample() - 0.5 r = qua[i0_qua,0] c = qua[i0_qua,1] r_radius = np.random.sample()*(radius_max-radius_min) + radius_min c_radius = np.random.sample()*(radius_max-radius_min) + radius_min rot = np.random.sample()*360 rr, cc = ellipse( r, c, r_radius, c_radius, rotation=np.deg2rad(rot), shape=img_l.shape ) p0 = np.rint(np.random.sample()*(radius_max-radius_min) + radius_min) p1 = qua[i1_qua,0] - (radius_max-radius_min) p2 = qua[i1_qua,1] - (radius_max-radius_min) p3 = np.rint(np.random.sample()*radius_min) p4 = np.rint(np.random.sample()*radius_min) p5 = np.rint(np.random.sample()*radius_min) p6 = np.rint(np.random.sample()*radius_min) p7 = np.rint(np.random.sample()*radius_min) p8 = np.rint(np.random.sample()*radius_min) poly = np.array(( (p1, p2), (p1+p3, p2+p4+p0), (p1+p5+p0, p2+p6+p0), (p1+p7+p0, p2+p8), (p1, p2), )) rr_p, cc_p = polygon(poly[:, 0], poly[:, 1], img_l.shape) if p > 0: img[:,:,:1] = img_l.copy() img[rr, cc,:1] = img_h[rr, cc] img[rr_p, cc_p,:1] = img_h[rr_p, cc_p] else: img[:,:,:1] = img_h.copy() img[rr, cc,:1] = img_l[rr, cc] img[rr_p, cc_p,:1] = img_l[rr_p, cc_p] img[:,:,1] = 0. img[:,:,1] = 0. img[rr_p, cc_p,1] = 1. img[:,:,2] = 0. p_f = np.random.sample()*1000. if p_f > 10: img[rr_p, cc_p,2] = 1. else: img[rr, cc,2] = 1. i_false[idx] = 1 return img 

Spickzettel-Berechnungsprogramm
 def make_sh(f_imgs, f_msks, val_len): precision = 0.85 batch_size = 50 t = tqdm() t_batch_size = 50 raw_len = val_len id_train = 1 #id_select = 1 v_false = np.zeros((train_num), dtype='float') while True: if id_train == 1: fit = model.fit(f_imgs[m2_select>0], f_msks[m2_select>0], batch_size=batch_size, epochs=1, verbose=0 ) current_accu = fit.history['my_iou_metric'][0] current_loss = fit.history['loss'][0] if current_accu > precision: id_train = 0 else: t_pred = model.predict( f_imgs[raw_len: min(raw_len+t_batch_size,f_imgs.shape[0])], batch_size=batch_size ) for kk in range(t_pred.shape[0]): val_iou = get_iou_vector( f_msks[raw_len+kk].reshape(1,w_size,w_size,1), t_pred[kk].reshape(1,w_size,w_size,1) > 0.5) v_false[raw_len+kk] = val_iou if val_iou < precision*0.95: new_img_test = 1 m2_select[raw_len+kk] = 1 val_len += 1 break raw_len += (kk+1) id_train = 1 t.set_description("Accuracy {0:6.4f} loss {1:6.4f} selected img {2:5d} tested img {3:5d} ". format(current_accu, current_loss, val_len, raw_len)) t.update(1) if raw_len >= train_num: break t.close() return v_false 


Das Hauptprogramm der Berechnungen. Wir haben kleine Änderungen am gleichen Programm gegenüber dem vorherigen Beitrag vorgenommen und einige Variablen müssen erklärt und kommentiert werden.

 i_false = np.zeros((train_num), dtype='int') 

Es gibt eine falsche Maske. Wenn 1, stimmt die Maske von F_msks nicht mit der Maske von f_msks überein. Dies ist ein Indikator dafür, wonach wir tatsächlich suchen - falsche Masken.

 m2_select = np.zeros((train_num), dtype='int') 

Zeigt an, dass dieses Bild im Spickzettel ausgewählt ist.

 batch_size = 50 val_len = batch_size + 1 # i_false - false mask marked as 1 i_false = np.zeros((train_num), dtype='int') # t_imgs, t_msks -test images and masks _txy = [next_pair_f(idx) for idx in range(train_num)] t_imgs = np.array(_txy)[:,:,:,:1].reshape(-1,w_size ,w_size ,1) t_msks = np.array(_txy)[:,:,:,1].reshape(-1,w_size ,w_size ,1) # m2_select - initial 51 pair m2_select = np.zeros((train_num), dtype='int') for k in range(val_len): m2_select[k] = 1 # i_false - false mask marked as 1 i_false = np.zeros((train_num), dtype='int') _txy = [next_pair_f(idx) for idx in range(train_num)] f_imgs = np.array(_txy)[:,:,:,:1].reshape(-1,w_size ,w_size ,1) f_msks = np.array(_txy)[:,:,:,1].reshape(-1,w_size ,w_size ,1) # F_msks - mask array with ~1% false mask F_msks = np.array(_txy)[:,:,:,2].reshape(-1,w_size ,w_size ,1) fig, axes = plt.subplots(2, 10, figsize=(20, 5)) for k in range(10): kk = np.random.randint(train_num) axes[0,k].set_axis_off() axes[0,k].imshow(f_imgs[kk].squeeze(), cmap="gray", norm=NoNorm()) axes[1,k].set_axis_off() axes[1,k].imshow(f_msks[kk].squeeze(), cmap="gray", norm=NoNorm()) plt.show(block=True) false_num = np.arange(train_num)[i_false>0] fig, axes = plt.subplots(3, 10, figsize=(20, 7)) for k in range(10): kk = np.random.randint(false_num.shape[0]) axes[0,k].set_axis_off() axes[0,k].set_title(false_num[kk]) axes[0,k].imshow(f_imgs[false_num[kk]].squeeze(), cmap="gray", norm=NoNorm()) axes[1,k].set_axis_off() axes[1,k].imshow(f_msks[false_num[kk]].squeeze(), cmap="gray", norm=NoNorm()) axes[2,k].set_axis_off() axes[2,k].imshow(F_msks[false_num[kk]].squeeze(), cmap="gray", norm=NoNorm()) plt.show(block=True) 

Wir erstellen Sequenzen von Bild / Masken-Paaren für das Training und eine weitere Sequenz zum Testen. Das heißt, Wir werden eine neue, unabhängige Sequenz von 10.000 Paaren prüfen. Wir zeigen zufällige Bilder mit echten und falschen Masken an und überprüfen sie visuell selektiv. Die obigen Bilder werden gezeigt.

In diesem speziellen Fall wurden 93 falsche Masken erhalten, auf denen eine Ellipse anstelle eines Vierecks als wahr positiv markiert wurde.

Wir beginnen mit dem Training am richtigen Satz und verwenden f_msks als Maske

 input_layer = Input((w_size, w_size, 1)) output_layer = build_model(input_layer, 25) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-4), metrics=[my_iou_metric]) v_false = make_sh(f_imgs, f_msks, val_len) t_pred = model.predict(t_imgs,batch_size=batch_size) print (get_iou_vector(t_msks,t_pred.reshape(-1,w_size ,w_size ,1))) 

 Accuracy 0.9807 loss 0.0092 selected img 404 tested img 10000 : : 1801it [08:13, 3.65it/s] 0.9895299999999841 

Der Spickzettel stellte sich in nur 404 Bildern heraus und erhielt eine akzeptable Genauigkeit in einer unabhängigen Testsequenz.

Jetzt kompilieren wir das Netzwerk neu und trainieren in derselben Trainingssequenz, aber als Masken geben wir F_msks mit 1% falschen Masken an die Eingabe weiter

 input_layer = Input((w_size, w_size, 1)) output_layer = build_model(input_layer, 25) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-4), metrics=[my_iou_metric]) v_false = make_sh(f_imgs, F_msks, val_len) t_pred = model.predict(t_imgs,batch_size=batch_size) print (get_iou_vector(t_msks,t_pred.reshape(-1,w_size ,w_size ,1))) 

 Accuracy 0.9821 loss 0.0324 selected img 727 tested img 10000 : : 1679it [25:44, 1.09it/s] 0.9524099999999959 

Wir haben einen Spickzettel mit 727 Bildern erhalten, der deutlich größer ist, und die Genauigkeit der Testvorhersagen, wie in der vorherigen Testsequenz, hat sich von 0,98953 auf 0,9525 verringert. Wir haben die Trainingssequenz um weniger als 1% um Lügen erweitert, nur 93 von 10.000 Masken waren falsch, aber das Ergebnis verschlechterte sich um 3,7%. Und das ist nicht nur eine Lüge, es ist eine echte List! Und der Spickzettel stieg von nur 404 auf bereits 727 Bilder.

Beruhigend und angenehm nur eine Sache

 print (len(set(np.arange(train_num)[m2_select>0]).intersection(set(np.arange(train_num)[i_false>0])))) 93 

Lassen Sie mich diese lange Formel erklären. Wir nehmen den Schnittpunkt der im Spickzettel ausgewählten Bilder mit der Menge der falschen Bilder und sehen, dass der Algorithmus alle 93 falschen Bilder im Spickzettel ausgewählt hat.

Die Aufgabe wird erheblich vereinfacht, es sind nicht 10.000 Bilder, die manuell durchgesehen werden müssen, es sind nur 727 und alle Lügen sind hier konzentriert.

Aber es gibt noch einen interessanteren und nützlicheren Weg. Bei der Zusammenstellung des Spickzettel haben wir nur die Bild / Masken-Paare aufgenommen, deren Vorhersage unter dem Schwellenwert liegt, und in unserem speziellen Fall haben wir den Wert der Vorhersagegenauigkeit im Array v_false gespeichert . Schauen wir uns Paare aus der Trainingssequenz an, die einen sehr kleinen Vorhersagewert haben, beispielsweise weniger als 0,1, und sehen, wie viele dort liegen

 print (len(set(np.arange(train_num)[v_false<0.01]).intersection(set(np.arange(train_num)[i_false>0])))) 89 


Wie Sie sehen können, fiel der Hauptteil der falschen Masken, 89 von 93, in diese Masken
 np.arange(train_num)[v_false<0.01].shape (382,) 

Wenn wir also nur 382 Masken manuell überprüfen und dies von 10.000 Teilen ist, werden wir die meisten falschen Masken ohne Mitleid identifizieren und zerstören.

Wenn es möglich ist, Bilder und Masken während der Entscheidung, sie in den Spickzettel aufzunehmen, anzuzeigen, werden ausgehend von einem Schritt alle falschen Masken, alle Lügen durch die Mindestvorhersagestufe eines leicht trainierten Netzwerks bestimmt, und die richtigen Masken haben eine Vorhersage, die größer als diese Stufe ist .

Zusammenfassend


Wenn in einer imaginären Welt die Wahrheit immer viereckig ist und die ovale Lüge und eine unbekannte Entität beschlossen, die Wahrheit zu verzerren und einige Ellipsen die Wahrheit nennen, und die Vierecke falsch sind, dann wird die lokale Inquisition unter Verwendung künstlicher Intelligenz und der natürlichen Fähigkeit, Spickzettel zu erstellen, schnell und einfach finden und beseitigt Lügen und Betrug vollständig und vollständig.

PS Die Fähigkeit, Ovale, Dreiecke und einfache Polygone zu erkennen, ist eine Voraussetzung für die Erstellung einer KI, die das Auto steuert. Wenn Sie nicht wissen, wie Sie nach Ovalen und Dreiecken suchen sollen, finden Sie nicht alle Verkehrszeichen und Ihre KI fährt im falschen Auto ab.

Source: https://habr.com/ru/post/de440120/


All Articles