एक साधारण यू-नेट के गुणों का एक छोटा अध्ययन, विभाजन के लिए एक क्लासिक दृढ़ नेटवर्क

लेख समुद्र में जहाजों की खोज के लिए प्रतियोगिता की सामग्री के विश्लेषण और अध्ययन पर लिखा गया है।

छवि

आइए समझने की कोशिश करें कि नेटवर्क कैसे और क्या खोज रहा है और यह क्या पाता है। यह लेख केवल जिज्ञासा और निष्क्रिय रुचि का परिणाम है, इसका कुछ भी व्यवहार में नहीं पाया गया है और व्यावहारिक कार्यों के लिए कॉपी-पेस्ट के लिए कुछ भी नहीं है। लेकिन परिणाम पूरी तरह से अपेक्षित नहीं है। इंटरनेट नेटवर्क के संचालन के विवरणों से भरा है जिसमें लेखक खूबसूरती से और चित्रों के साथ बताते हैं कि कैसे नेटवर्क आदिम - कोण, मंडलियों, मूंछ, पूंछ आदि का निर्धारण करते हैं, फिर उन्हें विभाजन / वर्गीकरण के लिए खोजा जाता है। कई प्रतियोगिताओं को अन्य बड़े और व्यापक नेटवर्क से वेट का उपयोग करके जीता जाता है। यह समझना और देखना दिलचस्प है कि एक नेटवर्क कैसे और कैसी प्राइमिटिव बनाता है।

हम एक छोटा अध्ययन करेंगे और विकल्पों पर विचार करेंगे - लेखक का तर्क और कोड प्रस्तुत किया गया है, आप स्वयं सब कुछ देख / बदल / बदल सकते हैं।

कागल समुद्री खोज प्रतियोगिता हाल ही में समाप्त हुई है। एयरबस ने जहाजों के साथ और बिना समुद्र के उपग्रह चित्रों का विश्लेषण करने का प्रस्ताव दिया। कुल 192555 चित्र 768x768x3 340 720 680 960 बाइट्स हैं अगर uint8 और चार गुना ज्यादा अगर फ्लोट 32 (वैसे फ्लोट 32 फ्लोट64 की तुलना में तेज है, कम मेमोरी एक्सेस) और 15606 चित्रों को ढूंढने की आवश्यकता है। हमेशा की तरह, सभी महत्वपूर्ण स्थानों को ओडीएस (ओडेसाई) में शामिल लोगों द्वारा लिया गया था, जो स्वाभाविक और अपेक्षित है, और मुझे आशा है कि हम जल्द ही विचार की ट्रेन और विजेताओं और पुरस्कार विजेताओं के कोड का अध्ययन कर पाएंगे।

हम एक समान समस्या पर विचार करेंगे, लेकिन हम इसे काफी सरल करेंगे - समुद्री np.random.sample () * 0.5 लें, हमें लहरों, हवा, तटों और अन्य छिपे हुए पैटर्न और चेहरे की आवश्यकता नहीं है। आरजीबी रेंज में 0.0 से 0.5 तक समुद्र की छवि को वास्तव में यादृच्छिक बनाते हैं। हम जहाजों को एक ही रंग में रंगेंगे और उन्हें समुद्र से अलग करने के लिए, हम उन्हें 0.5 से 1.0 तक की सीमा में रखेंगे, और वे सभी एक ही आकार के होंगे - विभिन्न आकारों और झुकावों के दीर्घवृत्त।

छवि

नेटवर्क का एक बहुत ही सामान्य संस्करण लें (आप अपना पसंदीदा नेटवर्क ले सकते हैं) और हम इसके साथ सभी प्रयोग करेंगे।

अगला, हम चित्र के मापदंडों को बदल देंगे, हस्तक्षेप पैदा करेंगे और परिकल्पना का निर्माण करेंगे - इसलिए हम उन मुख्य विशेषताओं को उजागर करते हैं जिनके द्वारा नेटवर्क दीर्घवृत्त पाता है। शायद पाठक अपने निष्कर्ष निकालेंगे और लेखक का खंडन करेंगे।

हम पुस्तकालयों को लोड करते हैं, हम चित्रों की एक सरणी का आकार निर्धारित करते हैं
import numpy as np import pandas as pd import matplotlib.pyplot as plt %matplotlib inline import math from tqdm import tqdm_notebook, tqdm from skimage.draw import ellipse, polygon from keras import Model from keras.callbacks import EarlyStopping, ModelCheckpoint, ReduceLROnPlateau from keras.models import load_model from keras.optimizers import Adam from keras.layers import Input, Conv2D, Conv2DTranspose, MaxPooling2D, concatenate, Dropout from keras.losses import binary_crossentropy import tensorflow as tf import keras as keras from keras import backend as K from tqdm import tqdm_notebook w_size = 256 train_num = 8192 train_x = np.zeros((train_num, w_size, w_size,3), dtype='float32') train_y = np.zeros((train_num, w_size, w_size,1), dtype='float32') img_l = np.random.sample((w_size, w_size, 3))*0.5 img_h = np.random.sample((w_size, w_size, 3))*0.5 + 0.5 radius_min = 10 radius_max = 30 


नुकसान और सटीकता कार्यों का निर्धारण करें
 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 }) 


हम छवि विभाजन में क्लासिक मीट्रिक का उपयोग करते हैं, बहुत सारे लेख हैं, चयनित मीट्रिक के बारे में टिप्पणियों और पाठ के साथ कोड, उसी कग्गल पर टिप्पणियों और स्पष्टीकरण के साथ बहुत सारे विकल्प हैं। हम पिक्सेल के मुखौटे की भविष्यवाणी करेंगे - यह "समुद्र" या "नाव" है और भविष्यवाणी की सच्चाई या झूठ का मूल्यांकन करता है। यानी निम्नलिखित चार विकल्प संभव हैं - हमने सही ढंग से भविष्यवाणी की कि एक पिक्सेल "समुद्र" है, सही ढंग से भविष्यवाणी की है कि एक पिक्सेल "जहाज" है या "समुद्र" या "जहाज" की भविष्यवाणी करने में गलती की है। और इसलिए, सभी चित्रों और सभी पिक्सेल के लिए, हम सभी चार विकल्पों की संख्या का अनुमान लगाते हैं और परिणाम की गणना करते हैं - यह नेटवर्क का परिणाम होगा। और कम त्रुटिपूर्ण भविष्यवाणियां और अधिक सत्य, परिणाम जितना सटीक और बेहतर नेटवर्क।

और अनुसंधान के लिए, चलो अच्छी तरह से अध्ययन किए गए यू-नेट लेते हैं, जो छवि विभाजन के लिए एक उत्कृष्ट नेटवर्क है। इस तरह की प्रतियोगिताओं में नेटवर्क बहुत आम है और कई विवरण, आवेदन की सूक्ष्मताएं आदि हैं। क्लासिक यू-नेट का एक संस्करण चुना गया था और निश्चित रूप से, इसे अपग्रेड करना, अवशिष्ट ब्लॉकों को जोड़ना आदि संभव था। लेकिन "आप अपरिपक्वता को गले नहीं लगा सकते" और एक ही बार में सभी प्रयोगों और परीक्षणों का संचालन करते हैं यू-नेट चित्रों के साथ एक बहुत ही सरल ऑपरेशन करता है - यह तस्वीर के आकार को कुछ परिवर्तनों के साथ कदम से कम करता है और फिर संपीड़ित छवि से मुखौटा को पुनर्प्राप्त करने की कोशिश करता है। यानी हमारे मामले में चित्र का आयाम 32x32 तक लाया जाता है और फिर हम पिछले सभी कंप्रेशन से डेटा का उपयोग करके मास्क को पुनर्स्थापित करने का प्रयास करते हैं।

तस्वीर में, यू-नेट योजना मूल लेख से है, लेकिन हम इसे थोड़ा सा फिर से करते हैं, लेकिन सार एक ही रहता है - हम छवि को संपीड़ित करते हैं → एक मुखौटा में विस्तार करते हैं।

छवि

बस यू-नेट
 def build_model(input_layer, start_neurons): 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 = MaxPooling2D((2, 2))(conv1) pool1 = Dropout(0.25)(pool1) 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 = MaxPooling2D((2, 2))(conv2) pool2 = Dropout(0.5)(pool2) 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 = MaxPooling2D((2, 2))(conv3) pool3 = Dropout(0.5)(pool3) 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 = MaxPooling2D((2, 2))(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) 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) 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) 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) 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 


पहला प्रयोग। सरलतम


हमारे प्रयोग का पहला संस्करण बहुत सरल होने के लिए सादगी के लिए चुना गया था - समुद्र हल्का है, जहाज गहरे हैं। सब कुछ बहुत सरल और स्पष्ट है, हम इस बात की परिकल्पना करते हैं कि नेटवर्क बिना किसी समस्या के और बिना किसी सटीकता के जहाजों / एलिप्स को खोजेगा। अगला_पेयर फ़ंक्शन चित्र / मास्क की एक जोड़ी बनाता है, जिसमें जगह, आकार, रोटेशन कोण को यादृच्छिक रूप से चुना जाता है। इसके अलावा, इस फ़ंक्शन में सभी परिवर्तन किए जाएंगे - रंग, आकार, हस्तक्षेप आदि में परिवर्तन। लेकिन अब सबसे आसान विकल्प, हम एक हल्के पृष्ठभूमि पर अंधेरे नौकाओं की परिकल्पना का परीक्षण करते हैं।

 def next_pair(): p = np.random.sample() - 0.5 #    # r,c -    r = np.random.sample()*(w_size-2*radius_max) + radius_max c = np.random.sample()*(w_size-2*radius_max) + radius_max #      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 ) #     #   /    0.5  1.0 img = img_h.copy() #       0.0  0.5 img[rr, cc] = img_l[rr, cc] msk = np.zeros((w_size, w_size, 1), dtype='float32') msk[rr, cc] = 1. #     return img, msk 

हम पूरी ट्रेन तैयार करते हैं और देखते हैं कि क्या हुआ। यह समुद्र में नावों जैसा दिखता है और इससे ज्यादा कुछ नहीं। सब कुछ स्पष्ट, स्पष्ट और समझने योग्य दिखाई देता है। स्थान यादृच्छिक है और प्रत्येक चित्र में केवल एक दीर्घवृत्त है।

 for k in range(train_num): #   img train img, msk = next_pair() train_x[k] = img train_y[k] = msk fig, axes = plt.subplots(2, 10, figsize=(20, 5)) #    10   for k in range(10): axes[0,k].set_axis_off() axes[0,k].imshow(train_x[k]) axes[1,k].set_axis_off() axes[1,k].imshow(train_y[k].squeeze()) 

छवि

इसमें कोई संदेह नहीं है कि नेटवर्क सफलतापूर्वक सीखेगा और दीर्घवृत्त ढूंढेगा। लेकिन हमें हमारी परिकल्पना का परीक्षण करना चाहिए कि नेटवर्क को दीर्घवृत्त / जहाजों को खोजने के लिए प्रशिक्षित किया गया है और एक ही समय में उच्च सटीकता के साथ।

 input_layer = Input((w_size, w_size, 3)) output_layer = build_model(input_layer, 16) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-3), metrics=[my_iou_metric]) model.save_weights('./keras.weights') while True: history = model.fit(train_x, train_y, batch_size=32, epochs=1, verbose=1, validation_split=0.1 ) if history.history['my_iou_metric'][0] > 0.75: break 

Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 55s 7ms/step - loss: 0.2272 - my_iou_metric: 0.7325 - val_loss: 0.0063 - val_my_iou_metric: 1.0000
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 53s 7ms/step - loss: 0.0090 - my_iou_metric: 1.0000 - val_loss: 0.0045 - val_my_iou_metric: 1.0000


नेटवर्क सफलतापूर्वक दीर्घवृत्त पाता है। लेकिन यह बिल्कुल भी सिद्ध नहीं है कि वह मनुष्य की समझ में दीर्घवृत्त की तलाश कर रही है, क्योंकि एक क्षेत्र जो दीर्घवृत्त समीकरण से घिरा है और पृष्ठभूमि से अलग सामग्री से भरा है, वहाँ कोई निश्चितता नहीं है कि द्विघात समीकरण के गुणांक के समान नेटवर्क भार हैं। और यह स्पष्ट है कि दीर्घवृत्त की चमक पृष्ठभूमि की चमक से कम है और कोई रहस्य या पहेली नहीं है - हम मानते हैं कि हमने सिर्फ कोड की जांच की है। चलो स्पष्ट चेहरे को ठीक करते हैं, दीर्घवृत्त की पृष्ठभूमि और रंग को भी यादृच्छिक बनाते हैं।

दूसरा विकल्प


अब एक ही समुद्र पर एक ही अंडाकार हैं, लेकिन समुद्र का रंग और, तदनुसार, नाव को यादृच्छिक रूप से चुना जाता है। यदि समुद्र गहरा है, तो जहाज हल्का और इसके विपरीत होगा। यानी अंकों के समूह की चमक से यह निर्धारित करना असंभव है कि क्या वे दीर्घवृत्त के बाहर हैं, यानी समुद्र या ये दीर्घवृत्त के अंदर के बिंदु हैं। फिर, हम अपनी परिकल्पना का परीक्षण करते हैं कि नेटवर्क को रंग की परवाह किए बिना दीर्घवृत्त मिलेगा।

 def next_pair(): p = np.random.sample() - 0.5 #    / r = np.random.sample()*(w_size-2*radius_max) + radius_max c = np.random.sample()*(w_size-2*radius_max) + radius_max 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 ) if p > 0: #     img = img_l.copy() img[rr, cc] = img_h[rr, cc] else: #     img = img_h.copy() img[rr, cc] = img_l[rr, cc] msk = np.zeros((w_size, w_size, 1), dtype='float32') msk[rr, cc] = 1. return img, msk 

अब, पिक्सेल और उसके आस-पास, पृष्ठभूमि या दीर्घवृत्त निर्धारित करना असंभव है। हम चित्र और मुखौटे भी बनाते हैं और स्क्रीन पर पहले 10 को देखते हैं।

बिल्डिंग मास्क
 for k in range(train_num): img, msk = next_pair() train_x[k] = img train_y[k] = msk fig, axes = plt.subplots(2, 10, figsize=(20, 5)) for k in range(10): axes[0,k].set_axis_off() axes[0,k].imshow(train_x[k]) axes[1,k].set_axis_off() axes[1,k].imshow(train_y[k].squeeze()) 



छवि
 input_layer = Input((w_size, w_size, 3)) output_layer = build_model(input_layer, 16) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-3), metrics=[my_iou_metric]) model.load_weights('./keras.weights', by_name=False) while True: history = model.fit(train_x, train_y, batch_size=32, epochs=1, verbose=1, validation_split=0.1 ) if history.history['my_iou_metric'][0] > 0.75: break 

Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 56s 8ms/step - loss: 0.4652 - my_iou_metric: 0.5071 - val_loss: 0.0439 - val_my_iou_metric: 0.9005
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 55s 7ms/step - loss: 0.1418 - my_iou_metric: 0.8378 - val_loss: 0.0377 - val_my_iou_metric: 0.9206


नेटवर्क आसानी से नकल करता है और सभी दीर्घवृत्त पाता है। लेकिन यहां, कार्यान्वयन में एक दोष है, और सब कुछ स्पष्ट है - तस्वीर में दो क्षेत्रों में से छोटा एक दीर्घवृत्त, एक और पृष्ठभूमि है। शायद यह एक गलत परिकल्पना है, लेकिन फिर भी इसे ठीक करें, दीर्घवृत्त के समान रंग की तस्वीर में एक और बहुभुज जोड़ें।

तीसरा विकल्प


प्रत्येक तस्वीर में, हम बेतरतीब ढंग से दो विकल्पों में से समुद्र के रंग का चयन करते हैं और एक दीर्घवृत्त और एक आयत जोड़ते हैं, जो दोनों समुद्र के रंग से अलग हैं। यह एक ही "समुद्र", एक चित्रित "नाव" भी निकलता है, लेकिन एक ही तस्वीर में हम "नाव" के रूप में एक ही रंग की एक आयत जोड़ते हैं और एक यादृच्छिक रूप से चयनित आकार के साथ भी। अब हमारी धारणा अधिक जटिल है, तस्वीर में दो पहचान की रंगीन वस्तुएं हैं, लेकिन हम इस बात की परिकल्पना करते हैं कि नेटवर्क अभी भी सही वस्तु का चयन करना सीखेगा।

दीर्घवृत्त और आयत बनाने के लिए कार्यक्रम
 def next_pair(): #        p = np.random.sample() - 0.5 r = np.random.sample()*(w_size-2*radius_max) + radius_max c = np.random.sample()*(w_size-2*radius_max) + radius_max 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 ) p1 = np.rint(np.random.sample()*(w_size-2*radius_max) + radius_max) p2 = np.rint(np.random.sample()*(w_size-2*radius_max) + radius_max) p3 = np.rint(np.random.sample()*(2*radius_max - radius_min) + radius_min) p4 = np.rint(np.random.sample()*(2*radius_max - radius_min) + radius_min) #   /,    poly = np.array(( (p1, p2), (p1, p2+p4), (p1+p3, p2+p4), (p1+p3, p2), (p1, p2), )) rr_p, cc_p = polygon(poly[:, 0], poly[:, 1], img_l.shape) in_sc = list(set(rr) & set(rr_p)) #   ,    #     #        if len(in_sc) > 0: if np.mean(rr_p) > np.mean(in_sc): poly += np.max(in_sc) - np.min(in_sc) else: poly -= np.max(in_sc) - np.min(in_sc) rr_p, cc_p = polygon(poly[:, 0], poly[:, 1], img_l.shape) if p > 0: img = img_l.copy() img[rr, cc] = img_h[rr, cc] img[rr_p, cc_p] = img_h[rr_p, cc_p] else: img = img_h.copy() img[rr, cc] = img_l[rr, cc] img[rr_p, cc_p] = img_l[rr_p, cc_p] msk = np.zeros((w_size, w_size, 1), dtype='float32') msk[rr, cc] = 1. return img, msk 


पहले की तरह, हम चित्रों और मुखौटों की गणना करते हैं और पहले 10 जोड़ों को देखते हैं।

मुखौटा चित्रों को दीर्घवृत्त और आयतों का निर्माण
 for k in range(train_num): img, msk = next_pair() train_x[k] = img train_y[k] = msk fig, axes = plt.subplots(2, 10, figsize=(20, 5)) for k in range(10): axes[0,k].set_axis_off() axes[0,k].imshow(train_x[k]) axes[1,k].set_axis_off() axes[1,k].imshow(train_y[k].squeeze()) 



छवि
 input_layer = Input((w_size, w_size, 3)) output_layer = build_model(input_layer, 16) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-3), metrics=[my_iou_metric]) model.load_weights('./keras.weights', by_name=False) while True: history = model.fit(train_x, train_y, batch_size=32, epochs=1, verbose=1, validation_split=0.1 ) if history.history['my_iou_metric'][0] > 0.75: break 

Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 57s 8ms/step - loss: 0.7557 - my_iou_metric: 0.0937 - val_loss: 0.2510 - val_my_iou_metric: 0.4580
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 55s 7ms/step - loss: 0.0719 - my_iou_metric: 0.8507 - val_loss: 0.0183 - val_my_iou_metric: 0.9812


नेटवर्क की आयतों को भ्रमित करना संभव नहीं था और हमारी परिकल्पना की पुष्टि की जाती है। उदाहरणों और चर्चाओं को देखते हुए, एयरबस प्रतियोगिता में सभी के पास एकल जहाज थे, और कई जहाज बिल्कुल सटीक थे। आयत से दीर्घवृत्त - i.e. जहाज घर से किनारे पर है, नेटवर्क प्रतिष्ठित है, हालांकि बहुभुज दीर्घवृत्तों के समान रंग हैं। यह रंग की बात नहीं है, दीर्घवृत्त और आयत दोनों के लिए समान रूप से यादृच्छिक रूप से चित्रित किया गया है।

चौथा विकल्प


शायद नेटवर्क आयतों द्वारा प्रतिष्ठित है - सही, उन्हें विकृत करें। यानी नेटवर्क आसानी से आकार की परवाह किए बिना दोनों बंद क्षेत्रों को ढूंढता है और एक आयत है कि यह बताता है। यह लेखक की परिकल्पना है - हम इसकी जाँच करेंगे, जिसके लिए हम आयतें नहीं जोड़ेंगे, बल्कि मनमाने आकार के चतुष्कोणीय बहुभुज भी होंगे। और फिर, हमारी परिकल्पना यह है कि नेटवर्क एक ही रंग के एक मनमाने चतुर्भुज बहुभुज से एक दीर्घवृत्त को अलग करता है।

आप निश्चित रूप से नेटवर्क के अंदरूनी हिस्सों में जा सकते हैं और वहां परतों को देख सकते हैं और वजन और बदलाव के अर्थ का विश्लेषण कर सकते हैं। लेखक नेटवर्क के परिणामी व्यवहार में रुचि रखता है, निर्णय कार्य के परिणाम पर आधारित होगा, हालांकि अंदर देखना हमेशा दिलचस्प होता है।

छवि निर्माण में बदलाव करें
 def next_pair(): p = np.random.sample() - 0.5 r = np.random.sample()*(w_size-2*radius_max) + radius_max c = np.random.sample()*(w_size-2*radius_max) + radius_max 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 = np.rint(np.random.sample()*(w_size-radius_max)) p2 = np.rint(np.random.sample()*(w_size-radius_max)) p3 = np.rint(np.random.sample()*2.*radius_min - radius_min) p4 = np.rint(np.random.sample()*2.*radius_min - radius_min) p5 = np.rint(np.random.sample()*2.*radius_min - radius_min) p6 = np.rint(np.random.sample()*2.*radius_min - radius_min) p7 = np.rint(np.random.sample()*2.*radius_min - radius_min) p8 = np.rint(np.random.sample()*2.*radius_min - 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) in_sc = list(set(rr) & set(rr_p)) if len(in_sc) > 0: if np.mean(rr_p) > np.mean(in_sc): poly += np.max(in_sc) - np.min(in_sc) else: poly -= np.max(in_sc) - np.min(in_sc) rr_p, cc_p = polygon(poly[:, 0], poly[:, 1], img_l.shape) if p > 0: img = img_l.copy() img[rr, cc] = img_h[rr, cc] img[rr_p, cc_p] = img_h[rr_p, cc_p] else: img = img_h.copy() img[rr, cc] = img_l[rr, cc] img[rr_p, cc_p] = img_l[rr_p, cc_p] msk = np.zeros((w_size, w_size, 1), dtype='float32') msk[rr, cc] = 1. return img, msk 


हम चित्रों और मुखौटों की गणना करते हैं और पहले 10 जोड़ों को देखते हैं।

हम चित्र मास्क दीर्घवृत्त और बहुभुज बनाते हैं
 for k in range(train_num): img, msk = next_pair() train_x[k] = img train_y[k] = msk fig, axes = plt.subplots(2, 10, figsize=(20, 5)) for k in range(10): axes[0,k].set_axis_off() axes[0,k].imshow(train_x[k]) axes[1,k].set_axis_off() axes[1,k].imshow(train_y[k].squeeze()) 



छवि
हम अपना नेटवर्क लॉन्च करते हैं। आपको याद दिला दूं कि यह सभी विकल्पों के लिए समान है।

 input_layer = Input((w_size, w_size, 3)) output_layer = build_model(input_layer, 16) model = Model(input_layer, output_layer) model.compile(loss=bce_dice_loss, optimizer=Adam(lr=1e-3), metrics=[my_iou_metric]) model.load_weights('./keras.weights', by_name=False) while True: history = model.fit(train_x, train_y, batch_size=32, epochs=1, verbose=1, validation_split=0.1 ) if history.history['my_iou_metric'][0] > 0.75: break 

Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 56s 8ms/step - loss: 0.6815 - my_iou_metric: 0.2168 - val_loss: 0.2078 - val_my_iou_metric: 0.4983
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 53s 7ms/step - loss: 0.1470 - my_iou_metric: 0.6396 - val_loss: 0.1046 - val_my_iou_metric: 0.7784
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 53s 7ms/step - loss: 0.0642 - my_iou_metric: 0.8586 - val_loss: 0.0403 - val_my_iou_metric: 0.9354

परिकल्पना की पुष्टि की जाती है, बहुभुज और दीर्घवृत्त आसानी से भिन्न होते हैं। एक चौकस पाठक यहाँ ध्यान देगा - बेशक वे अलग हैं, एक बकवास सवाल है, कोई भी सामान्य एआई पहले की रेखा से दूसरे क्रम के एक वक्र को भेद सकता है। यानी नेटवर्क आसानी से दूसरे क्रम के वक्र के रूप में एक सीमा की उपस्थिति को निर्धारित करता है। हम बहस नहीं करेंगे, अंडाकार को एक हेप्टागन और चेक के साथ बदलें।

पांचवां प्रयोग, सबसे कठिन


कोई वक्र नहीं हैं, केवल नियमित रूप से झुकाव और घुमाए गए हेप्टैगोन और मनमाने ढंग से चतुष्कोणीय बहुभुज के चिकनी चेहरे हैं। हम फ़ंक्शन में छवि / मुखौटा जनरेटर परिवर्तन का परिचय देते हैं - केवल एक ही रंग के नियमित हेप्टैगॉन और मनमाने ढंग से चतुष्कोणीय बहुभुज के अनुमान।

छवि निर्माण समारोह का अंतिम संशोधन
 def next_pair(_n = 7): p = np.random.sample() - 0.5 c_x = np.random.sample()*(w_size-2*radius_max) + radius_max c_y = np.random.sample()*(w_size-2*radius_max) + radius_max radius = np.random.sample()*(radius_max-radius_min) + radius_min d = np.random.sample()*0.5 + 1 a_deg = np.random.sample()*360 a_rad = np.deg2rad(a_deg) poly = [] #    for k in range(_n): #     # _ _ -  poly.append(c_x+radius*math.sin(2.*k*math.pi/_n)) poly.append(c_y+radius*math.cos(2.*k*math.pi/_n)) # \  #    0.5  1.5  poly[-2] = (poly[-2]-c_x)/d +c_x poly[-1] = (poly[-1]-c_y) +c_y #     poly[-2] = ((poly[-2]-c_x)*math.cos(a_rad)\ - (poly[-1]-c_y)*math.sin(a_rad)) + c_x poly[-1] = ((poly[-2]-c_x)*math.sin(a_rad)\ + (poly[-1]-c_y)*math.cos(a_rad)) + c_y poly = np.rint(poly).reshape(-1,2) rr, cc = polygon(poly[:, 0], poly[:, 1], img_l.shape) p0 = np.rint(np.random.sample()*(radius_max-radius_min) + radius_min) p1 = np.rint(np.random.sample()*(w_size-radius_max)) p2 = np.rint(np.random.sample()*(w_size-radius_max)) p3 = np.rint(np.random.sample()*2.*radius_min - radius_min) p4 = np.rint(np.random.sample()*2.*radius_min - radius_min) p5 = np.rint(np.random.sample()*2.*radius_min - radius_min) p6 = np.rint(np.random.sample()*2.*radius_min - radius_min) p7 = np.rint(np.random.sample()*2.*radius_min - radius_min) p8 = np.rint(np.random.sample()*2.*radius_min - 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) in_sc = list(set(rr) & set(rr_p)) if len(in_sc) > 0: if np.mean(rr_p) > np.mean(in_sc): poly += np.max(in_sc) - np.min(in_sc) else: poly -= np.max(in_sc) - np.min(in_sc) rr_p, cc_p = polygon(poly[:, 0], poly[:, 1], img_l.shape) if p > 0: img = img_l.copy() img[rr, cc] = img_h[rr, cc] img[rr_p, cc_p] = img_h[rr_p, cc_p] else: img = img_h.copy() img[rr, cc] = img_l[rr, cc] img[rr_p, cc_p] = img_l[rr_p, cc_p] msk = np.zeros((w_size, w_size, 1), dtype='float32') msk[rr, cc] = 1. return img, msk 


पहले की तरह, हम ऐरे बनाते हैं और पहले 10 को देखते हैं।

बिल्डिंग मास्क
 for k in range(train_num): img, msk = next_pair() train_x[k] = img train_y[k] = msk fig, axes = plt.subplots(2, 10, figsize=(20, 5)) for k in range(10): axes[0,k].set_axis_off() axes[0,k].imshow(train_x[k]) axes[1,k].set_axis_off() axes[1,k].imshow(train_y[k].squeeze()) 


छवि
 input_layer = Input((w_size, w_size, 3)) output_layer = build_model(input_layer, 16) model = Model(input_layer, output_layer) model.compile(loss=dice_loss, optimizer=Adam(lr=1e-3), metrics=[my_iou_metric]) model.load_weights('./keras.weights', by_name=False) while True: history = model.fit(train_x, train_y, batch_size=32, epochs=1, verbose=1, validation_split=0.1 ) if history.history['my_iou_metric'][0] > 0.75: break 

Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 54s 7ms/step - loss: 0.5005 - my_iou_metric: 0.1296 - val_loss: 0.1692 - val_my_iou_metric: 0.3722
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 52s 7ms/step - loss: 0.1287 - my_iou_metric: 0.4522 - val_loss: 0.0449 - val_my_iou_metric: 0.6833
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 52s 7ms/step - loss: 0.0759 - my_iou_metric: 0.5985 - val_loss: 0.0397 - val_my_iou_metric: 0.7215
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 52s 7ms/step - loss: 0.0455 - my_iou_metric: 0.6936 - val_loss: 0.0297 - val_my_iou_metric: 0.7304
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 52s 7ms/step - loss: 0.0432 - my_iou_metric: 0.7053 - val_loss: 0.0215 - val_my_iou_metric: 0.7846
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 53s 7ms/step - loss: 0.0327 - my_iou_metric: 0.7417 - val_loss: 0.0171 - val_my_iou_metric: 0.7970
Train on 7372 samples, validate on 820 samples
Epoch 1/1
7372/7372 [==============================] - 52s 7ms/step - loss: 0.0265 - my_iou_metric: 0.7679 - val_loss: 0.0138 - val_my_iou_metric: 0.8280


परिणाम


जैसा कि आप देख सकते हैं, नेटवर्क परीक्षण के सेट पर 0.828 की सटीकता के साथ नियमित हेप्टैगन और मनमाने ढंग से चतुष्कोणीय बहुभुजों के अनुमानों के बीच अंतर करता है। नेटवर्क प्रशिक्षण को 0.75 के मनमाने मूल्य से रोका जाता है और सबसे अधिक संभावना सटीकता बेहतर होनी चाहिए। यदि हम उस थीसिस से आगे बढ़ते हैं जो नेटवर्क प्राइमिटिव्स को ढूंढता है और उनके संयोजन ऑब्जेक्ट को निर्धारित करते हैं, तो हमारे मामले में पृष्ठभूमि से एक अलग औसत के साथ दो क्षेत्र हैं, मनुष्य की समझ में कोई आदिम नहीं हैं। कोई स्पष्ट, एक-रंग की रेखाएं नहीं हैं, और क्रमशः कोई कोने नहीं हैं, केवल बहुत समान सीमाओं वाले क्षेत्र हैं। यहां तक ​​कि अगर आप लाइनों का निर्माण करते हैं, तो तस्वीर में दोनों ऑब्जेक्ट एक ही आदिम से निर्मित होते हैं।

पारखी लोगों के लिए एक प्रश्न - नेटवर्क क्या संकेत मानता है जिसके द्वारा वह "नौकाओं" को "हस्तक्षेप" से अलग करता है? जाहिर है, यह नावों की सीमाओं का रंग या आकार नहीं है। बेशक, हम आगे "समुद्री" / "जहाजों" के इस अमूर्त निर्माण का अध्ययन करना जारी रख सकते हैं, हम विज्ञान अकादमी नहीं हैं और पूरी तरह से जिज्ञासा से अनुसंधान का संचालन कर सकते हैं। हम हेप्टैगन्स को ऑक्टागॉन में बदल सकते हैं या नियमित पांच और छह कोणों से चित्र भर सकते हैं और देख सकते हैं कि उनका नेटवर्क अलग है या नहीं। मैं इसे पाठकों के लिए छोड़ देता हूं - हालांकि मुझे यह भी आश्चर्य होता है कि क्या नेटवर्क बहुभुज के कोनों की संख्या की गणना कर सकता है और परीक्षण के लिए, तस्वीर में नियमित रूप से बहुभुज नहीं, बल्कि उनके यादृच्छिक अनुमानों की व्यवस्था करें।

ऐसी नौकाओं के कोई अन्य दिलचस्प गुण नहीं हैं, और इस तरह के प्रयोग उपयोगी हैं कि हम स्वयं अध्ययन किए गए सेट की सभी संभाव्य विशेषताओं को निर्धारित करते हैं और अच्छी तरह से अध्ययन किए गए नेटवर्क के अप्रत्याशित व्यवहार ज्ञान को जोड़ेंगे और लाभ लाएंगे।

बेतरतीब ढंग से चयनित पृष्ठभूमि, रंग का चयन बेतरतीब ढंग से, नाव / दीर्घवृत्त स्थान को यादृच्छिक रूप से चुना गया। तस्वीरों में कोई रेखाएं नहीं हैं, विभिन्न विशेषताओं वाले क्षेत्र हैं, लेकिन एक-रंग की रेखाएं नहीं हैं! इस मामले में, निश्चित रूप से, सरलीकरण हैं और कार्य आगे जटिल हो सकता है - उदाहरण के लिए, 0.0 ... 0.9 और 0.1 ... 1.0 जैसे रंग चुनें - लेकिन नेटवर्क के लिए कोई अंतर नहीं है। नेटवर्क उन पैटर्नों को खोज और ढूंढ सकता है जो उन लोगों से अलग हैं जो एक व्यक्ति स्पष्ट रूप से देखता है और पाता है।

यदि पाठकों में से कोई भी दिलचस्पी रखता है, तो आप नेटवर्क पर शोध करना और चुनना जारी रख सकते हैं, अगर वह काम नहीं करता है या स्पष्ट नहीं है, या यदि कोई नया और अच्छा विचार प्रकट होता है और उसकी सुंदरता के साथ प्रभावित होता है, तो आप हमेशा हमारे साथ साझा कर सकते हैं या स्वामी (और दादी) से भी पूछ सकते हैं और ODS समुदाय में योग्य मदद के लिए पूछें।

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


All Articles