keras 自定义ImageDataGenerator用于多标签分类

网友投稿 311 2022-09-15

keras 自定义ImageDataGenerator用于多标签分类

感想

keras提供了flow_from_directory用于单个标签分类,但是对图片的多标签分类没有支持,这就需要我们自己动手实现ImageDataGenerator,我这里把我实现的用于多标签分类的自定义DataGenerator分享出来,读者可以根据自己的情况来进行修改。

数据集我用的是经过整理了之后的NUS-WIDE数据集,

数据集的网盘链接:链接:提取码:hpxg 复制这段内容后打开百度网盘手机App,操作更方便哦

我的数据集放在一个txt文档里面的,我这里展示一下我的txt文件的example:

actor\0013_1106962433.jpg* streetactor\0018_470960261.jpg* wateractor\0031_2406153318.jpg* dog gardenactor\0033_213660760.jpg* planeactor\0034_569936943.jpg* dancingactor\0041_2456602544.jpg* road sky streetactor\0049_2163720456.jpg* streetactor\0064_2343195092.jpg* buildingsactor\0081_2159186964.jpg* skyactor\0211_2233188435.jpg* beach sandactor\0213_1850366878.jpg* sun sunsetactor\0219_453334665.jpg* foxactor\0224_954526140.jpg* streetactor\0229_433478352.jpg* sky sun sunsetactor\0231_637866194.jpg* fox tattooactor\0258_1053942091.jpg* beachactor\0273_2727864150.jpg* streetactor\0279_2321264821.jpg* statue templeactor\0284_2060799990.jpg* runningactor\0333_82685319.jpg* streetactor\0378_344147378.jpg* statueactor\0393_173349342.jpg* flowersactor\0435_522150101.jpg* cars toweractor\0438_2504620853.jpg* streetactor\0448_2291046386.jpg* skyactor\0463_2483322510.jpg* clouds skyactor\0485_292906123.jpg* road vehicleactor\0491_335496963.jpg* police road street toy trainactor\0495_870673543.jpg* runningactor\0530_2568827539.jpg* book

可以看到*左边为图片的路径,右边为图片所对应的标签,然后我给每个标签编了一个号,命名为word_id.txt:

0 dog1 clouds2 tree3 garden4 dancing5 toy6 fox7 ocean8 tower9 police10 lake11 mountain12 fish13 town14 reflection15 water16 rocks17 animal18 temple19 bear20 grass21 sun22 beach23 sky24 street25 snow26 vehicle27 birds28 plane29 book30 sand31 road32 statue33 bridge34 cars35 cat36 flowers37 military38 buildings39 airport40 window41 train42 computer43 tattoo44 sunset45 person46 running47 house

创建word_id.txt的代码为create_word_id.py:

txt_path='datasets81_train.txt'with open(txt_path,'r') as f: datasets=f.readlines()word_dict=set()for file in datasets: data_arr=file.strip().split('*') img=data_arr[0] tag_list=data_arr[1].split(' ') for i in range(1,len(tag_list)): word_dict.add(tag_list[i].strip())id_tag_path='word_id.txt'with open(id_tag_path,'w') as f: for i,tag in enumerate(word_dict): f.write(str(i)+' '+tag+'\n')

最后自己定义了一个Generator:

import osfrom PIL import Imageimport numpy as npBATCHSIZE=10root_path='/home/eric/data/NUS-WIDE/image'class data_generator: def __init__(self,file_path,_max_example,image_size,classes): self.load_data(file_path=file_path) self.index=0 self.batch_size=BATCHSIZE self.image_size=image_size self.classes=classes self.load_images_labels(_max_example) self.num_of_examples=_max_example def load_data(self,file_path): with open(file_path,'r') as f: self.datasets=f.readlines() def load_images_labels(self,_max_example): images=[] labels=[] for i in range(0,len(self.datasets[:_max_example])): data_arr=self.datasets[i].strip().split('*') image_path=os.path.join(root_path,data_arr[0]).replace("\\", "/") img=Image.open(image_path) img = img.resize((self.image_size[0], self.image_size[1]),Image.ANTIALIAS) img=np.array(img) images.append(img) tags=data_arr[1].split(' ') label=np.zeros((self.classes)) for i in range(1,len(tags)): # print(word_id[tags[i]]) id=int(word_id[tags[i]]) label[id]=1 labels.append(label) self.images=images self.labels=labels def get_mini_batch(self): while True: batch_images=[] batch_labels=[] for i in range(self.batch_size): if(self.index==len(self.images)): self.index=0 batch_images.append(self.images[self.index]) batch_labels.append(self.labels[self.index]) self.index+=1 batch_images=np.array(batch_images) batch_labels=np.array(batch_labels) yield batch_images,batch_labelsid_tag_path='word_id.txt'word_id={}with open(id_tag_path,'r') as f: words=f.readlines() for item in words: arr=item.strip().split(' ') word_id[arr[1]]=arr[0]if __name__ == "__main__": txt_path='datasets81_clean.txt' width,height=224,224 IMAGE_SIZE=(width,height,3) classes=81 train_gen=data_generator(txt_path,100,IMAGE_SIZE,classes) x,y=next(train_gen.get_mini_batch()) print(x.shape) print(y.shape)

我们看看train.py的调用:

from keras.optimizers import *from keras.callbacks import *from keras.models import *from DataGenerator import data_generatorfrom resnet50 import ResNet50from measure import *train_txt_path='datasets81_train.txt'test_txt_path='datasets81_test.txt'width,height=224,224IMAGE_SIZE=(width,height,3)classes=81model_name='resnet50'train_gen=data_generator(train_txt_path,100,IMAGE_SIZE,classes)val_gen=data_generator(test_txt_path,100,IMAGE_SIZE,classes)model = ResNet50.resnet(IMAGE_SIZE,classes=classes)model.summary()save_path=os.path.join('trained_model',model_name)if(not os.path.exists(save_path)): os.makedirs(save_path)tensorboard = TensorBoard(log_dir='./logs/{}'.format(model_name), batch_size=train_gen.batch_size)model_names = (os.path.join(save_path,model_name+'.{epoch:02d}-{val_acc:.4f}.hdf5'))model_checkpoint = ModelCheckpoint(model_names, monitor='val_acc', verbose=1, save_best_only=True, save_weights_only=False)reduce_learning_rate = ReduceLROnPlateau(monitor='val_loss', factor=0.1, patience=5, verbose=1)callbacks = [model_checkpoint,reduce_learning_rate,tensorboard]model.compile(optimizer = 'adam', loss='binary_crossentropy', metrics=['accuracy',fmeasure,recall,precision])steps=train_gen.num_of_examples//train_gen.batch_sizeepochs=50model.fit_generator(generator=train_gen.get_mini_batch(augment=True),steps_per_epoch=steps, epochs=epochs, callbacks=callbacks, validation_data=val_gen.get_mini_batch(), validation_steps=val_gen.num_of_examples // val_gen.batch_size, verbose=1)

其中的precision,recall , fmeasure的代码如下,这是从某人分享中截取出来的,具体出处未知了哈measure.py:

import keras.backend as Kdef precision(y_true, y_pred): # Calculates the precision true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) predicted_positives = K.sum(K.round(K.clip(y_pred, 0, 1))) precision = true_positives / (predicted_positives + K.epsilon()) return precisiondef recall(y_true, y_pred): # Calculates the recall true_positives = K.sum(K.round(K.clip(y_true * y_pred, 0, 1))) possible_positives = K.sum(K.round(K.clip(y_true, 0, 1))) recall = true_positives / (possible_positives + K.epsilon()) return recalldef fbeta_score(y_true, y_pred, beta=1): # Calculates the F score, the weighted harmonic mean of precision and recall. if beta < 0: raise ValueError('The lowest choosable beta is zero (only precision).') # If there are no true positives, fix the F score at 0 like sklearn. if K.sum(K.round(K.clip(y_true, 0, 1))) == 0: return 0 p = precision(y_true, y_pred) r = recall(y_true, y_pred) bb = beta ** 2 fbeta_score = (1 + bb) * (p * r) / (bb * p + r + K.epsilon()) return fbeta_scoredef fmeasure(y_true, y_pred): # Calculates the f-measure, the harmonic mean of precision and recall. return fbeta_score(y_true, y_pred, beta=1)

我这里用到了resnet50的代码,这里也分享出来:

import osfrom keras.layers import ( Conv2D, BatchNormalization, MaxPooling2D, ZeroPadding2D, AveragePooling2D, add, Dense, Flatten,Input)from keras.layers.advanced_activations import PReLUfrom keras.models import Model, load_model# from utils import load_mnistclass ResNet50(): @staticmethod def resnet(input_shape,classes=100,weights="trained_model/resnet.hdf5"): """Inference function for ResNet y = resnet(X) Parameters ---------- input_tensor : keras.layers.Input Returns ---------- y : softmax output """ def name_builder(type, stage, block, name): return "{}{}{}_branch{}".format(type, stage, block, name) def identity_block(input_tensor, kernel_size, filters, stage, block): F1, F2, F3 = filters def name_fn(type, name): return name_builder(type, stage, block, name) x = Conv2D(F1, (1, 1), name=name_fn('res', '2a'))(input_tensor) x = BatchNormalization(name=name_fn('bn', '2a'))(x) x = PReLU()(x) x = Conv2D(F2, kernel_size, padding='same', name=name_fn('res', '2b'))(x) x = BatchNormalization(name=name_fn('bn', '2b'))(x) x = PReLU()(x) x = Conv2D(F3, (1, 1), name=name_fn('res', '2c'))(x) x = BatchNormalization(name=name_fn('bn', '2c'))(x) x = PReLU()(x) x = add([x, input_tensor]) x = PReLU()(x) return x def conv_block(input_tensor, kernel_size, filters, stage, block, strides=(2, 2)): def name_fn(type, name): return name_builder(type, stage, block, name) F1, F2, F3 = filters x = Conv2D(F1, (1, 1), strides=strides, name=name_fn("res", "2a"))(input_tensor) x = BatchNormalization(name=name_fn("bn", "2a"))(x) x = PReLU()(x) x = Conv2D(F2, kernel_size, padding='same', name=name_fn("res", "2b"))(x) x = BatchNormalization(name=name_fn("bn", "2b"))(x) x = PReLU()(x) x = Conv2D(F3, (1, 1), name=name_fn("res", "2c"))(x) x = BatchNormalization(name=name_fn("bn", "2c"))(x) sc = Conv2D(F3, (1, 1), strides=strides, name=name_fn("res", "1"))(input_tensor) sc = BatchNormalization(name=name_fn("bn", "1"))(sc) x = add([x, sc]) x = PReLU()(x) return x input_tensor = Input(shape=input_shape) net = ZeroPadding2D((3, 3))(input_tensor) net = Conv2D(64, (7, 7), strides=(2, 2), name="conv1")(net) net = BatchNormalization(name="bn_conv1")(net) net = PReLU()(net) net = MaxPooling2D((3, 3), strides=(2, 2))(net) net = conv_block(net, 3, [64, 64, 256], stage=2, block='a', strides=(1, 1)) net = identity_block(net, 3, [64, 64, 256], stage=2, block='b') net = identity_block(net, 3, [64, 64, 256], stage=2, block='c') net = conv_block(net, 3, [128, 128, 512], stage=3, block='a') net = identity_block(net, 3, [128, 128, 512], stage=3, block='b') net = identity_block(net, 3, [128, 128, 512], stage=3, block='c') net = identity_block(net, 3, [128, 128, 512], stage=3, block='d') net = conv_block(net, 3, [256, 256, 1024], stage=4, block='a') net = identity_block(net, 3, [256, 256, 1024], stage=4, block='b') net = identity_block(net, 3, [256, 256, 1024], stage=4, block='c') net = identity_block(net, 3, [256, 256, 1024], stage=4, block='d') net = identity_block(net, 3, [256, 256, 1024], stage=4, block='e') net = identity_block(net, 3, [256, 256, 1024], stage=4, block='f') net = AveragePooling2D((2, 2))(net) net = Flatten()(net) net = Dense(classes, activation="sigmoid")(net) model = Model(input_tensor, net, name='model') if os.path.isfile(weights): model.load_weights(weights) print("Model loaded") else: print("No model is found") return model# img_width=128# img_height=128# charset_size=6941# model = ResNet50.resnet(input_shape=(img_width,img_height,3), classes=charset_size)# model.summary()

然后就可以运行了。

版权声明:本文内容由网络用户投稿,版权归原作者所有,本站不拥有其著作权,亦不承担相应法律责任。如果您发现本站中有涉嫌抄袭或描述失实的内容,请联系我们jiasou666@gmail.com 处理,核实后本网站将在24小时内删除侵权内容。

上一篇:[leetcode] 414. Third Maximum Number
下一篇:全媒派:从10万到50万,美国报业如何报道新冠死亡人数?
相关文章

 发表评论

暂时没有评论,来抢沙发吧~