Перейти к содержимому
Compvision.ru

prim.ko

Пользователи
  • Количество публикаций

    42
  • Зарегистрирован

  • Посещение

  • Days Won

    2

Все публикации пользователя prim.ko

  1. Приветствую. Начал разбираться с сеткой UNet. Нашел реализацию на Keras + Theano, которой на кагле сегментировали нервы. В конкурсе изображения имели бинарные маски. А как подготавливать и скармливать сетке маски, если имеем несколько классов? Есть примеры кода? И как создавать такие маски? Это будут просто заранее заданные цвета, или лучше перевести в градации серого с одним каналом? Вот пример реализации UNet, где мужик подготавливает данные в *npy from __future__ import print_function import os from skimage.transform import resize from skimage.io import imsave import numpy as np from keras.models import Model from keras.layers import Input, concatenate, Conv2D, MaxPooling2D, UpSampling2D from keras.optimizers import Adam from keras.callbacks import ModelCheckpoint from keras import backend as K from data import load_train_data, load_test_data #prepare train data def create_train_data(): train_data_path = os.path.join(data_path, 'train') images = os.listdir(train_data_path) total = len(images) / 2 # учитываем маски и тренировочные imgs = np.ndarray((total, image_rows, image_cols), dtype=np.uint8) imgs_mask = np.ndarray((total, image_rows, image_cols), dtype=np.uint8) i = 0 print('-'*30) print('Creating training images...') print('-'*30) for image_name in images: if 'mask' in image_name: continue image_mask_name = image_name.split('.')[0] + '_mask.tif' img = imread(os.path.join(train_data_path, image_name), as_grey=True) img_mask = imread(os.path.join(train_data_path, image_mask_name), as_grey=True) img = np.array([img]) img_mask = np.array([img_mask]) imgs[i] = img imgs_mask[i] = img_mask if i % 100 == 0: print('Done: {0}/{1} images'.format(i, total)) i += 1 print('Loading done.') np.save('imgs_train.npy', imgs) np.save('imgs_mask_train.npy', imgs_mask) print('Saving to .npy files done.') from __future__ import print_function img_rows = 96 img_cols = 96 smooth = 1. def dice_coef(y_true, y_pred): y_true_f = K.flatten(y_true) y_pred_f = K.flatten(y_pred) intersection = K.sum(y_true_f * y_pred_f) return (2. * intersection + smooth) / (K.sum(y_true_f) + K.sum(y_pred_f) + smooth) def dice_coef_loss(y_true, y_pred): return -dice_coef(y_true, y_pred) def get_unet(): inputs = Input((img_rows, img_cols, 1)) conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(inputs) conv1 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv1) pool1 = MaxPooling2D(pool_size=(2, 2))(conv1) conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(pool1) conv2 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv2) pool2 = MaxPooling2D(pool_size=(2, 2))(conv2) conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(pool2) conv3 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv3) pool3 = MaxPooling2D(pool_size=(2, 2))(conv3) conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(pool3) conv4 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv4) pool4 = MaxPooling2D(pool_size=(2, 2))(conv4) conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(pool4) conv5 = Conv2D(512, (3, 3), activation='relu', padding='same')(conv5) up6 = concatenate([UpSampling2D(size=(2, 2))(conv5), conv4], axis=3) conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(up6) conv6 = Conv2D(256, (3, 3), activation='relu', padding='same')(conv6) up7 = concatenate([UpSampling2D(size=(2, 2))(conv6), conv3], axis=3) conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(up7) conv7 = Conv2D(128, (3, 3), activation='relu', padding='same')(conv7) up8 = concatenate([UpSampling2D(size=(2, 2))(conv7), conv2], axis=3) conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(up8) conv8 = Conv2D(64, (3, 3), activation='relu', padding='same')(conv8) up9 = concatenate([UpSampling2D(size=(2, 2))(conv8), conv1], axis=3) conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(up9) conv9 = Conv2D(32, (3, 3), activation='relu', padding='same')(conv9) conv10 = Conv2D(1, (1, 1), activation='sigmoid')(conv9) model = Model(inputs=[inputs], outputs=[conv10]) model.compile(optimizer=Adam(lr=1e-5), loss=dice_coef_loss, metrics=[dice_coef]) return model def preprocess(imgs): imgs_p = np.ndarray((imgs.shape[0], img_rows, img_cols), dtype=np.uint8) for i in range(imgs.shape[0]): imgs_p[i] = resize(imgs[i], (img_cols, img_rows), preserve_range=True) imgs_p = imgs_p[..., np.newaxis] return imgs_p def train_and_predict(): print('-'*30) print('Loading and preprocessing train data...') print('-'*30) imgs_train, imgs_mask_train = load_train_data() imgs_train = preprocess(imgs_train) imgs_mask_train = preprocess(imgs_mask_train) imgs_train = imgs_train.astype('float32') mean = np.mean(imgs_train) # mean for data centering std = np.std(imgs_train) # std for data normalization imgs_train -= mean imgs_train /= std imgs_mask_train = imgs_mask_train.astype('float32') imgs_mask_train /= 255. # scale masks to [0, 1] print('-'*30) print('Creating and compiling model...') print('-'*30) model = get_unet() model_checkpoint = ModelCheckpoint('weights.h5', monitor='val_loss', save_best_only=True) print('-'*30) print('Fitting model...') print('-'*30) model.fit(imgs_train, imgs_mask_train, batch_size=32, nb_epoch=20, verbose=1, shuffle=True, validation_split=0.2, callbacks=[model_checkpoint]) print('-'*30) print('Loading and preprocessing test data...') print('-'*30) imgs_test, imgs_id_test = load_test_data() imgs_test = preprocess(imgs_test) imgs_test = imgs_test.astype('float32') imgs_test -= mean imgs_test /= std print('-'*30) print('Loading saved weights...') print('-'*30) model.load_weights('weights.h5') print('-'*30) print('Predicting masks on test data...') print('-'*30) imgs_mask_test = model.predict(imgs_test, verbose=1) np.save('imgs_mask_test.npy', imgs_mask_test) print('-' * 30) print('Saving predicted masks to files...') print('-' * 30) pred_dir = 'preds' if not os.path.exists(pred_dir): os.mkdir(pred_dir) for image, image_id in zip(imgs_mask_test, imgs_id_test): image = (image[:, :, 0] * 255.).astype(np.uint8) imsave(os.path.join(pred_dir, str(image_id) + '_pred.png'), image) if __name__ == '__main__': train_and_predict()
  2. Добрый день. Не совсем ясна одна вещь, связанная с преобразованием изображений. К примеру имеется изображение, полученное камерой. Камера внизсмотрящая. Известно положение камеры в мировом пространстве. Их однозначно определяет акселерометр. Мне необходимо воспользоваться данными с акселерометра для афинных преобразований полученного изображения. Как я понял для этого необходимо перевести координаты двумерных точек на изображении в однородные координаты [x,y]-> [x,y,1], и умножить вектор на матрицу поворота. Необходимо ли где-то использовать матрицу внутренних параметров камеры? В конечном итоге необходимо откорректировать проекцию изображения.
  3. Добрый день. Товарищи, кто сможет поделиться аккаунтом на https://www.cityscapes-dataset.com/login/ для скачивания датасета? Мне уже 2 недели не отвечают по двум заявкам.
  4. Так, ну вроде бы похоже на правду. Установил проверку на выход предсказания равному кол-ву классов, то есть 5 и пока работает вроде: if bottom[0].count != 5*bottom[1].count Не гуд вот, что: DIGITS не визуализирует отрицательную ошибку на графике:
  5. День добрый. Возникло желание прикрутить к caffe Jaccard index: Jaccard Тренирую сеть для задачи семантической сегментации, используя датасет с 5 классами. Непременно нужно прикрутить jaccard в python layer. Для этих целей я переделал код, который реализует dice loss: https://github.com/NVIDIA/DIGITS/tree/digits-5.0/examples/medical-imaging Получается, что я не совсем понимаю как устроены блобы в Caffe. Есть подозрение, что необходимо по-другому передавать axis, при суммировании всех предсказаний и масок: def forward(self, bottom, top): smooth = 1e-12 label = bottom[1].data[:,0,:,:] # compute prediction prediction = np.argmax(bottom[0].data, axis=1) # area of predicted contour a_p = np.sum(prediction, axis=self.sum_axes) # area of contour in label a_l = np.sum(label, axis=self.sum_axes) # area of intersection a_pl = np.sum(prediction * label, axis=self.sum_axes) # dice coefficient dice_coeff = np.mean((2.*a_pl+smooth)/(a_p + a_l+smooth)) top[0].data[...] = dice_coeff Получилась следующая реализация: import random import numpy as np import caffe import math class Jaccard(caffe.Layer): """ A layer that calculates the Jaccard coefficient """ def setup(self, bottom, top): if len(bottom) != 2: raise Exception("Need two inputs to compute Jaccard coefficient.") # compute sum over all axes but the batch and channel axes self.sum_axes = tuple(range(1, bottom[0].data.ndim - 1)) def reshape(self, bottom, top): # check input dimensions match if bottom[0].count != 2*bottom[1].count: raise Exception("Prediction must have twice the number of elements of the input.") # loss output is scalar top[0].reshape(1) def forward(self, bottom, top): smooth = 1e-12 label = bottom[1].data[:,0,:,:] # compute prediction prediction = np.argmax(bottom[0].data, axis=1) # area of predicted contour a_p = np.sum(prediction, axis=self.sum_axes) # area of contour in label a_l = np.sum(label, axis=self.sum_axes) # area of intersection a_pl = np.sum(prediction * label, axis=self.sum_axes) # jaccard coef jaccard_coef = np.mean((a_pl+smooth) / (a_p + a_l - a_pl + smooth)) jaccard_coef=0 top[0].data[...] = jaccard_coef def backward(self, top, propagate_down, bottom): if propagate_down[1]: raise Exception("label not diff") elif propagate_down[0]: #crossentropy loss_crossentropy = 0 for i in range(len(prediction)): loss_crossentropy = loss_crossentropy - prediction[i] * (label[i] - (prediction[i] >= 0)) - math.log(1 + math.exp(prediction[i] - 2 * prediction[i] * (prediction[i] >= 0))) bottom[0].diff[...] = -(math.log(jaccard_coef) + loss_crossentropy) else: raise Exception("no diff") Код ошибки error code 1. Если установить кол-во классов равное 2 и использовать код dice loss из вышеприведенной ссылки, все прекрасно заходит. Ошибка в индексах. Есть какие-нибудь соображения?
  6. Хороший обзор плат arm+fpga https://m.geektimes.ru/post/292803/
  7. finetuning

    На этот счет хочу еще проверить возможно ли будет загружать несколько классов в один модуль, используя один файл, но несколько python layers. Удобно для ошибки и data test aug будет использовать
  8. Добрый вечер. Интересует как можно обучить модель с использованием vgg-16 предобученной? В keras это как говорит @ternaus из ods "делается мизинцем левой ноги". Причем вообще не глядя в монитор. https://blog.keras.io/building-powerful-image-classification-models-using-very-little-data.html . А для Caffe можно так же просто? Интуитивно догадываюсь, что нужно как-то замораживать слои все сверточные и обучать только выход. И еще, например входы vgg-16 224*244*3. Моя сетка запрашивает на вход изображение 256*256. Изменять свою сеть?
  9. finetuning

    Интересная сетка. Для сегментации? С какой целью делаются множественные crop?
  10. finetuning

    То есть подход следующий, я правильно понял? 1) загружаем веса 2) Изменяем свою сеть. Объявляем столько слоев из прототипа модели VGG-16 сколько необходимо, в своем прототипе модели. Вот на этом моменте замораживаем добавленные слои. Здесь попрошу подробнее разъяснить. Свои слои при этом выбрасываются? Оставляются только выходы из своей модели? 3) Получили необходимый loss, возвращаем все слои на место?
  11. finetuning

    При этом память GPU больше потребляется, в отличие от обучения своей сеткой с нуля? В Keras понравилось, что мы предсказываем с VGG-16 в отдельной итерации на трогая память GPU. А тут как?
  12. error 1 всегда преследует созданный пользователем python файл. В данном случае функцию doAugmentation лучше поместить в класс RotationLayer import random import numpy as np import caffe class RotationLayer(caffe.Layer): def setup(self, bottom, top): print('In Setup') #assert len(bottom) == 2, 'requires 2 layer.bottom' #assert bottom[0].data.ndim >= 3, 'requires image data' #assert bottom[1].data.ndim >= 3, 'requires image data' #assert len(top) == 2, 'requires 2 layer.top' def reshape(self, bottom, top): # Copy shape from bottom print('In Reshape') #top[0].reshape(*bottom[0].data.shape) #top[1].reshape(*bottom[1].data.shape) def forward(self, bottom, top): # Copy all of the data print('In Forward') #top[0].data[...] = bottom[0].data[...] #top[1].data[...] = bottom[1].data[...] #for ii in xrange(0, top[0].data.shape[0]): # [top[0].data[ii, :, :, :],top[1].data[ii, :, :, :]] = doAugmentation(top[0].data[ii, :, :, :],top[1].data[ii, :, :, :]) def backward(self, top, propagate_down, bottom): pass def doAugmentation(self): print("aug") #print('In Augmentation') #ang=random.uniform(-30,30) #return [ndimage.rotate(img, ang, reshape=False),ndimage.rotate(mask, ang, reshape=False)] Если используешь DIGITS в определении модели можно указать module: "digits_python_layers"
  13. Есть замечательный туториал по работе с TensorRT и внутренней камерой jetsona. Там работает все без унылой OpenCV - на gstremer`e вытягивается сразу на GPU. Перепилил код под свои нужды и все замечательно. DetectNet к примеру на 2 класса выдает - 15 fps (480*360) https://github.com/dusty-nv/jetson-inference#image-segmentation-with-segnet
  14. Да. Jetson TX. Если не вру, то python layer вообще не участвует в deploy
  15. Ага, помню когда я взвешивал выборку camvid, в которой 325 картинок. , ну она еще с segnet идет в комплексе, получились немного другие цифры ежели у автора. Там даже issue открыли в git, в котором у народа такие же цифры вышли. Автор молчит:) Некоторые цифры в классах на порядок отличались. Caffè - потому что она единственная собирается без боли под TX*. К тому же есть TensoRT, которые вообще песня:)
  16. У меня выборка большая. Настроить BN было принципиально. Не знаю как обстоят дела с caffe, которую собирать ручками, в dockere так. Dice loss прикрутил. Довольно удобно оказалось, что можно юзать python layer. С ним другое дело. Стандартный softmaxwithloss грустно относится к неравномерно распределеным классам.
  17. В общем через боль, страдания, подбор параметров и еще танцев с бубном проблема решена. Надеюсь кому-то поможет эта информация. Почему-то по умолчанию в DIGITS ( использовал docker nvidia-digits-rc-6.0) в слое типа BatchNorm ( а может быть и в других слоях ) используется CUDNN engine в противовес CAFFE engine, если этого не задавать явно. Мужики пишут по этому поводу вот что: Теперь Caffe BN слой для использования его в DIGITS выглядит вот так: layer { name: "G9_d2_bn" type: "BatchNorm" bottom: "G9_d1_conv" top: "G9_d2_bn" param { #scale lr_mult: 1 decay_mult: 1 } param { #shift/bias lr_mult: 1 decay_mult: 1 } param { #global mean lr_mult: 0 decay_mult: 0 } param { #global var lr_mult: 0 decay_mult: 0 } batch_norm_param { scale_filler { type: "constant" value: 1 } bias_filler { type: "constant" value: 0 } engine: CUDNN use_global_stats: false } } Интересно, что при использовании CUDNN engine память gpu отжирается вот так: Если установить CAFFE engine: За одинаковое время обучения сеть с использованием CUDNN engine заврешила 15 эпох. С использованием CAFFE engine 7 эпох.
  18. Та модель, которую обучил - без bn. В keras я пробовал изменять модель после того как обучил. Добавлял слои и загружал веса от старой - так нельзя. В Caffè ведь так же
  19. При изменении данного параметра я никаких сдвигов не увидел. Я использовал 1е-6. У меня нет предобученной модели. Или речь идет например о VGG-16? Это возможно сюда прикрутить чтобы не обучаться с ноля? И поможет ли это в данном случае, ведь картинки спутниковые, а ImageNet содержит совсем другие классы. Опять таки почему с BN не работает?) Мало 70 эпох?
  20. Ясно. Значит можно просто установить размер батча равным 12 и не указывать "accumulation". Вообщем моя ошибка - поучил сеть 10 эпох и бежал смотреть вывод. По этому ничего и не показывала. Убрал все BN и поучил 70 эпох (600 картинок) вывод получил. Значит сеть учится. Но только почему с BN не учится? Установил даже lr_mult=1, decay_mult=1 Есть вопрос у меня еще по поводу функции активации. в оригинальном U-NET использовали dice loss либо jackard. Как возможно сюда это запилить? Получается глупая картинка при обучении: После первой эпохи accuracy достигает 0.94 и так и держится чуть-чуть (+- 0.001) изменяясь. Тут явно какой-то криминал. Последние слои сделал вот так: layer { name: "G10_a1_conv" type: "Convolution" bottom: "G9_d1_conv" top: "G10_a1_conv" convolution_param { num_output: 2 kernel_size: 1 pad: 0 engine: CUDNN weight_filler { type: "xavier" } bias_filler { type: "constant" value: 0 } } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "G10_a1_conv" bottom: "label" top: "loss" loss_param { normalize: true } exclude { stage: "deploy" } } layer { name: "accuracy" type: "Accuracy" bottom: "G10_a1_conv" bottom: "label" top: "accuracy" include { stage: "val" } } Есть предположения в чем может быть дело?
  21. Как это делается примерно? learning rate стоит изначально на 0.01 затем уменьшается с exponential Decay А про batch accumulation ребята вот что пишут на примере detectnet. На 1080 влазит размер батча 12 (картинки 256*256). По совету ребят вроде как нужно не больше единицы установить param { lr_mult: 0 decay_mult: 0 } Эти параметры не знал вообще что делают. Для чего их предназначение?
  22. Вроде как заработало, если исправить у последнего сверточного слоя "G10_a1_conv" параметр pad=0. В итоге вышла вот такая U-Net unet_train_new.prototxt . Вот только обучаться это чудо не хочет. Показывает при тестировании белые изображения. Причем при просмотре статистики Infer One Image.html только первый сверточный слой активируется нормально, а затем вообще ничего. Может это связано с вычитанием среднего?
  23. Использовал что-то похожее на https://github.com/NVIDIA/DIGITS/tree/master/examples/semantic-segmentation. Сконструировал всю сетку unet_train_new.prototxt . DIGITS ругается: Подаю ему вот такие данные: Не до конца понял, чего ему не нравится?
  24. Да, не обучается. Строю сетку и смотрю, на что caffe ругается. Пока не добавил Deconvolution layer. Добавил в модель слой deconv и accuracy и все заработало. Только конечно при тестировании обученной модели показывает темное изображение. выход не правильный? layer { name: "conv1a" type: "Convolution" bottom: "data" top: "conv1a" convolution_param { num_output: 32 kernel_size: 3 pad: 1 stride: 1 engine: CUDNN weight_filler { type: "xavier" #std: 0.01 } bias_filler { type: "constant" value: 0 } } } layer { name: "conv1a_BN" type: "BatchNorm" bottom: "conv1a" top: "conv1a_BN" param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } batch_norm_param { use_global_stats: false moving_average_fraction: 0.95 } } layer { name: "elu1" type: "ELU" elu_param { alpha: 1.0} bottom: "conv1a_BN" top: "conv1a_BN" } layer { name: "conv1b" type: "Convolution" bottom: "conv1a_BN" top: "conv1b" convolution_param { num_output: 32 kernel_size: 3 pad: 1 stride: 1 engine: CUDNN weight_filler { type: "xavier" } bias_filler { type: "constant" value: 0 } } } layer { name: "conv1b_BN" type: "BatchNorm" bottom: "conv1b" top: "conv1b_BN" param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } param { lr_mult: 0 decay_mult: 0 } batch_norm_param { use_global_stats: false moving_average_fraction: 0.95 } } layer { name: "elu2" type: "ELU" elu_param { alpha: 1.0} bottom: "conv1b_BN" top: "conv1b_BN" } layer { name: "pool1" type: "Pooling" bottom: "conv1b_BN" top: "pool1" pooling_param { pool: MAX kernel_size: 2 stride: 2 } } layer { name: "up_deconv1" type: "Deconvolution" bottom: "pool1" top: "up_deconv1" param { lr_mult: 1 decay_mult: 1 } convolution_param { num_output: 32 kernel_size: 2 stride: 2 } } layer { name: "loss" type: "SoftmaxWithLoss" bottom: "up_deconv1" bottom: "label" top: "loss" include: { phase: TRAIN } } layer { name: "accuracy" type: "Accuracy" bottom: "up_deconv1" bottom: "label" top: "accuracy" include { stage: "val" } }
×