Kecerdasan buatan versus kebohongan dan tipuan

Dalam semua tugas mengajar kecerdasan buatan, ada satu fenomena yang tidak menyenangkan - kesalahan dalam peningkatan urutan pelatihan. Kesalahan ini tidak dapat dihindari, karena semua markup dilakukan secara manual, karena jika ada cara untuk menandai data nyata secara terprogram, maka mengapa kita membutuhkan orang lain untuk mengajar mereka untuk menandai dan menghabiskan waktu dan uang untuk menciptakan desain yang benar-benar tidak perlu!

Tugas menemukan dan menghapus topeng palsu dalam urutan pelatihan besar cukup rumit. Anda dapat melihat semuanya secara manual, tetapi ini tidak akan menyelamatkan Anda dari kesalahan berulang. Tetapi jika Anda melihat dekat pada alat untuk mempelajari jaringan saraf yang diusulkan dalam posting sebelumnya , ternyata ada cara sederhana dan efektif untuk mendeteksi dan mengekstrak semua artefak dari urutan pelatihan.

Dan dalam posting ini ada contoh konkret, jelas bahwa yang sederhana, pada elips dan poligon, untuk U-net biasa, lagi-lagi seperti lego di kotak pasir, tetapi sangat beton, berguna dan efektif. Kami akan menunjukkan bagaimana metode sederhana mengidentifikasi dan menemukan hampir semua artefak, semua kebohongan dari urutan pelatihan.

Jadi mari kita mulai!

Seperti sebelumnya, kita akan mempelajari urutan pasangan gambar / topeng. Dalam gambar di tempat yang berbeda, dipilih secara acak, kita akan menempatkan elips dengan ukuran acak dan juga quadrangle dengan ukuran acak, dan keduanya berwarna dalam warna yang sama, juga secara acak memilih dua di antaranya. Pada warna kedua yang tersisa, kita mewarnai latar belakang. Dimensi elips dan segi empat tentu saja terbatas.

Tetapi dalam kasus ini, kami akan memperkenalkan perubahan ke dalam program pembuatan pasangan dan mempersiapkan, bersama dengan topeng yang sepenuhnya benar, yang salah, diracuni oleh kebohongan - dalam sekitar satu persen dari kasus, ganti segi empat pada topeng dengan elips, yaitu. objek sebenarnya untuk segmentasi dilambangkan dengan topeng palsu sebagai elips, bukan segiempat.

Contoh Acak 10



Contoh acak 10, tetapi dari markup yang salah. Topeng benar, yang lebih rendah salah, dan angka dalam urutan pelatihan ditunjukkan pada gambar.



untuk segmentasi, kami mengambil program perhitungan metrik dan kerugian yang sama dan U-net sederhana yang sama, tetapi kami tidak akan menggunakan Dropout.

Perpustakaan
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 


Fungsi Metrik dan Kehilangan
 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 }) 


U-net normal
 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() 


Program untuk menghasilkan gambar dan topeng - benar dan salah. Lapisan pertama dari gambar ditempatkan dalam array, yang kedua adalah topeng yang benar dan lapisan ketiga adalah topeng yang salah.

 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 

Program perhitungan lembar cheat
 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 


Program utama perhitungan. Kami membuat perubahan kecil pada program yang sama dari posting sebelumnya dan beberapa variabel memerlukan penjelasan dan komentar.

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

Ada indikator topeng salah. Jika 1, maka mask dari F_msks tidak cocok dengan mask dari f_msks. Ini adalah indikator dari apa yang sebenarnya kita cari - topeng palsu.

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

Indikator bahwa gambar ini dipilih pada lembar cheat.

 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) 

Kami membangun urutan pasangan gambar / topeng untuk pelatihan dan urutan lain untuk pengujian. Yaitu Kami akan memeriksa urutan 10.000 pasang baru yang independen. Kami menampilkan dan secara visual memeriksa gambar acak dengan topeng benar dan salah. Gambar-gambar di atas ditampilkan.

Dalam kasus khusus ini, 93 topeng palsu diperoleh, di mana elips, bukan segi empat, ditandai sebagai benar positif.

Kami memulai pelatihan pada set yang benar, gunakan f_msks sebagai mask

 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 

Lembar cheat ternyata hanya 404 gambar dan mendapat akurasi yang dapat diterima pada urutan tes independen.

Sekarang kita mengkompilasi ulang jaringan dan melatih pada urutan pelatihan yang sama, tetapi sebagai topeng kita memberi makan F_msks dengan 1% topeng palsu ke input

 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 

Kami mendapat lembar contekan berisi 727 gambar, yang secara signifikan lebih besar dan keakuratan prediksi pengujian, sama seperti pada urutan pengujian sebelumnya, menurun dari 0,98953 ke 0,9525. Kami menambahkan kebohongan pada urutan pelatihan kurang dari 1%, hanya 93 dari 10.000 topeng yang salah, tetapi hasilnya memburuk sebesar 3,7%. Dan ini bukan hanya kebohongan, itu benar-benar kelicikan! Dan lembar contekan meningkat dari hanya 404 menjadi 727 gambar.

Menenangkan dan menyenangkan hanya satu hal

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

Biarkan saya menjelaskan rumus panjang ini, kami mengambil persimpangan dari set gambar yang dipilih dalam lembar contekan dengan set gambar palsu dan melihat bahwa algoritma memilih semua 93 gambar palsu di lembar contekan.

Tugas ini disederhanakan secara signifikan, bukan 10.000 gambar untuk dilihat secara manual, hanya 727 dan semua kebohongan terkonsentrasi di sini.

Tetapi ada cara yang bahkan lebih menarik dan berguna. Ketika kami menyusun lembar contekan, kami hanya menyertakan pasangan gambar / topeng yang prediksinya kurang dari ambang, dan dalam kasus khusus kami, kami menyimpan nilai akurasi prediksi ke dalam array v_false . Mari kita lihat pasangan dari urutan pelatihan yang memiliki nilai prediksi yang sangat kecil, misalnya, kurang dari 0,1 dan lihat berapa banyak kebohongan di sana

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


Seperti yang Anda lihat bagian utama dari topeng palsu, 89 dari 93, jatuh ke topeng ini
 np.arange(train_num)[v_false<0.01].shape (382,) 

Jadi, jika kita memeriksa hanya 382 topeng secara manual, dan ini dari 10.000 keping, kita akan mengidentifikasi dan menghancurkan sebagian besar topeng palsu tanpa belas kasihan.

Jika dimungkinkan untuk melihat gambar dan topeng selama keputusan untuk memasukkannya ke dalam lembar contekan, maka mulai dari langkah, semua topeng palsu, semua kebohongan akan ditentukan oleh tingkat minimum prediksi jaringan yang sedikit terlatih, dan topeng yang benar akan memiliki prediksi yang lebih besar dari level ini .

Untuk meringkas


Jika di beberapa dunia yang dibayangkan kebenaran selalu berbentuk segi empat, dan kebohongan oval dan beberapa entitas yang tidak diketahui memutuskan untuk mendistorsi kebenaran dan menyebut beberapa elips kebenaran, dan quadrangles itu salah, maka, menggunakan kecerdasan buatan dan kemampuan alami untuk membuat lembar contekan, Inkuisisi lokal akan dengan cepat dan mudah menemukan dan memberantas kebohongan dan tipuan sepenuhnya dan sepenuhnya.

PS Kemampuan untuk mendeteksi oval, segitiga, dan poligon sederhana adalah prasyarat untuk membuat AI apa pun yang mengendalikan mobil. Jika Anda tidak tahu cara mencari oval dan segitiga, Anda tidak akan menemukan semua rambu lalu lintas dan AI Anda akan pergi dengan mobil yang salah.

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


All Articles