第一次参加kaggle的经验(小白专属)

    数据分析不是我所擅长的,可以直接使用别人的读取代码,有eda的更好了,省劲,首先找一个好的,可以提交的代码跑一下提交,这是第一步。

接下来,看看评论,哪种模型结构更好,站在巨人的肩膀上更轻松一点,现在主流都是残差网络了,需要尝试的也不是很多,如果比赛刚开始的话,不要着急,先进行数据分析,把数据下载下来不要着急,慢慢看,过一段时间评论会给出不少好的方案,还是一句话,站在巨人的肩膀上会更加轻松,第一次不需要尝试太多可能,先找一种跑跑看。
如果还没人开始,那就可以尝深度残差网络,resnet densenet efficientnet这三种网络,一般来说,这三个是老大了。
下面附一份keras的头文件

from tensorflow import keras

from keras.models import Model, Input, load_model

from keras.callbacks import ReduceLROnPlateau
from keras.callbacks import ModelCheckpoint
from keras.callbacks import EarlyStopping


from keras.preprocessing.image import ImageDataGenerator

from keras.layers import Dense
from keras.layers import Conv2D
from keras.layers import Flatten
from keras.layers import MaxPool2D
from keras.layers import Dropout
from keras.layers import BatchNormalization
from keras.layers import Input
from keras.layers import concatenate
from keras.layers import GlobalAveragePooling2D
from keras.layers import AveragePooling2D
from keras.layers import Activation
from keras.layers import GlobalMaxPooling2D
from keras.layers import Reshape
from keras.layers import multiply
from keras.layers import Permute
from keras.layers import Add
from keras.layers import Lambda
from keras import backend as K
from keras.activations import sigmoid

from keras.applications.vgg16 import VGG16
from keras.applications.vgg19 import VGG19
from keras.applications.inception_v3 import InceptionV3
from keras.applications.xception import Xception
from keras.applications.inception_resnet_v2 import InceptionResNetV2
from keras.applications.mobilenet import MobileNet
from keras.applications.nasnet import NASNetLarge
from keras.applications.nasnet import NASNetMobile
from keras.applications.mobilenet_v2 import MobileNetV2
from keras.applications import DenseNet121
from keras.applications import DenseNet169
from keras.applications import DenseNet201
from keras.applications.resnet import ResNet50
from keras.applications.resnet import ResNet101
from keras.applications.resnet import ResNet152
from keras.applications.resnet_v2 import ResNet50V2
from keras.applications.resnet_v2 import ResNet101V2
from keras.applications.resnet_v2 import ResNet152V2
# !pip install -q efficientnet

import efficientnet.tfkeras as efn
#使用
#model = efn.EfficientNetB0

basic_model= DenseNet121(weights="imagenet", include_top=False)

这是我整理的包含全部的常用的keras的头文件,直接建立一个cell复制过去就可以了,反正也不占很大空间,省心。
想换别的结构只需要把DenseNet121换了就可以了,这个有点基础就应该懂了。
再分享一个多输出的模型代码

def build_model():
    densenet = DenseNet121(weights="imagenet", include_top=False)

    input = Input(shape=(SIZE, SIZE, N_ch))
    x = Conv2D(1, (3, 3), padding='same')(input)
    x=concatenate([x,x,x])
    x = densenet(x)
    x = Dropout(0.5)(x)
    
    x = GlobalAveragePooling2D()(x)
#     x = BatchNormalization()(x)
#     x = Dropout(0.5)(x)
#     x = Dense(256, activation='relu')(x)
#     x = BatchNormalization()(x)
#     x = Dropout(0.5)(x)

    # multi output
    grapheme_root = Dense(types['grapheme_root'],
                          activation = 'softmax', name='root')(x)
    vowel_diacritic = Dense(types['vowel_diacritic'],
                            activation = 'softmax', name='vowel')(x)
    consonant_diacritic = Dense(types['consonant_diacritic'],
                                activation = 'softmax', name='consonant')(x)

    # model
    model = Model(input,
                  [grapheme_root, vowel_diacritic, consonant_diacritic])
    
    return model
model = build_model()

也可以用这种,其实差不多

def create_model():
    #pretrained_model = tf.keras.applications.MobileNetV2(input_shape=[*IMAGE_SIZE, 3], include_top=False)
    #pretrained_model = tf.keras.applications.Xception(input_shape=[*IMAGE_SIZE, 3], include_top=False)
    #pretrained_model = tf.keras.applications.VGG16(weights='imagenet', include_top=False ,input_shape=[*IMAGE_SIZE, 3])
    #pretrained_model = tf.keras.applications.ResNet50(weights='imagenet', include_top=False, input_shape=[*IMAGE_SIZE, 3])
    #pretrained_model = tf.keras.applications.MobileNet(weights='imagenet', include_top=False, input_shape=[*IMAGE_SIZE, 3])
    # EfficientNet can be loaded through efficientnet.tfkeras library (https://github.com/qubvel/efficientnet)
    pretrained_model = efn.EfficientNetB7(weights='imagenet', include_top=False)
    
    pretrained_model.trainable = True

    model = tf.keras.Sequential([
        pretrained_model,
        tf.keras.layers.GlobalAveragePooling2D(),        
        tf.keras.layers.Dense(num_classes, activation='softmax')
    ])

    model.compile(
        optimizer='adam',
        loss = 'categorical_crossentropy',
        metrics=['accuracy']
    )

    return model

#%%

model = create_model()
model.summary()

大概的使用现有的结构构造模型就是这样
在分享一个kaggle显示所有文件的,虽然这个建立的时候就会给,但是这么好的东西还是要发一下,偶尔可能忘记,因为在本地编辑会不写,直接上传可能就忘了

for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

接下里是一个数据增强,keras的数据增强还是很好的

class MultiOutputDataGenerator(keras.preprocessing.image.ImageDataGenerator):

    def flow(self,
             x,
             y=None,
             batch_size=32,
             shuffle=True,
             sample_weight=None,
             seed=None,
             save_to_dir=None,
             save_prefix='',
             save_format='png',
             subset=None):

        targets = None
        target_lengths = {}
        ordered_outputs = []
        for output, target in y.items():
            if targets is None:
                targets = target
            else:
                targets = np.concatenate((targets, target), axis=1)
            target_lengths[output] = target.shape[1]
            ordered_outputs.append(output)


        for flowx, flowy in super().flow(x, targets, batch_size=batch_size,
                                         shuffle=shuffle):
            target_dict = {}
            i = 0
            for output in ordered_outputs:
                target_length = target_lengths[output]
                target_dict[output] = flowy[:, i: i + target_length]
                i += target_length

            yield flowx, target_dict

使用方法

 datagen = MultiOutputDataGenerator(
            featurewise_center=False,  # set input mean to 0 over the dataset
            samplewise_center=False,  # set each sample mean to 0
            featurewise_std_normalization=False,  # divide inputs by std of the dataset
            samplewise_std_normalization=False,  # divide each input by its std
            zca_whitening=False,  # apply ZCA whitening
            rotation_range=8,  # randomly rotate images in the range (degrees, 0 to 180)
            zoom_range = 0.15, # Randomly zoom image 
            width_shift_range=0.15,  # randomly shift images horizontally (fraction of total width)
            height_shift_range=0.15,  # randomly shift images vertically (fraction of total height)
            horizontal_flip=False,  # randomly flip images
            vertical_flip=False)  # randomly flip images


        # This will just calculate parameters required to augment the given data. This won't perform any augmentations
        datagen.fit(x_train)

        # Fit the model
        history = model.fit_generator(datagen.flow(x_train, {'dense_23': y_train_root, 'dense_24': y_train_vowel, 'dense_25': y_train_consonant}, batch_size=batch_size),
                                  epochs = epochs, validation_data = (x_test, [y_test_root, y_test_vowel, y_test_consonant]), 
                                  steps_per_epoch=x_train.shape[0] // batch_size, 
                                  callbacks=[learning_rate_reduction_root, learning_rate_reduction_vowel, learning_rate_reduction_consonant]
                                     )

hiostory根据实际调整吧,有的时候数据增强不一定有用,挨个试选择有用的吧。

学习率是很重要的,sgd带动量和adam是最常用的,sgd上限高,adam的收敛速度快,自由选择
自动减少是个不错的选择,有耐心可以在多少轮之后在减少,这个需要放在callbacks里面

learning_rate_reduction = ReduceLROnPlateau(monitor='val_loss', 
                                            patience=3, 
                                            verbose=1,
                                            factor=0.2, 
                                            min_lr=0.000001)

sgd带动量,初始学习率也很关键,好象有的人说是3e-4来着,这个我没尝试过

sgd = keras.optimizers.SGD(lr=0.0001, decay=1e-6, momentum=0.9, nesterov=True)

在tpu花卉分类上我也看到一种不错的学习率调整

LR_START = 0.00001
LR_MAX = 0.00005 
LR_MIN = 0.00001
LR_RAMPUP_EPOCHS = 5
LR_SUSTAIN_EPOCHS = 0
LR_EXP_DECAY = .8

def lrfn(epoch):
    if epoch < LR_RAMPUP_EPOCHS:
        lr = (LR_MAX - LR_START) / LR_RAMPUP_EPOCHS * epoch + LR_START
    elif epoch < LR_RAMPUP_EPOCHS + LR_SUSTAIN_EPOCHS:
        lr = LR_MAX
    else:
        lr = (LR_MAX - LR_MIN) * LR_EXP_DECAY**(epoch - LR_RAMPUP_EPOCHS - LR_SUSTAIN_EPOCHS) + LR_MIN
    return lr
    
lr_callback = tf.keras.callbacks.LearningRateScheduler(lrfn, verbose=True)
 #callbacks=[lr_callback]

介绍模型的写法

 enet = efn.EfficientNetB7(
        input_shape=(512, 512, 3),
        weights='imagenet',
        include_top=False
    )

    model = tf.keras.Sequential([
        enet,
        tf.keras.layers.GlobalAveragePooling2D(),
        tf.keras.layers.Dense(len(CLASSES), activation='softmax')
    ])

Sequential非常好用,直接叠加非常方便的
模型融合是最后的方法了,原理很简单,预测的结果乘以一个系数,另一个乘以1减这个系数再用np.argmax,例如这样

probabilities = best_alpha*model.predict(test_images_ds) + (1-best_alpha)*model2.predict(test_images_ds)
predictions = np.argmax(probabilities, axis=-1)

显示训练的图像也很重要


def display_training_curves(training, validation, title, subplot):
    if subplot%10==1: # set up the subplots on the first call
        plt.subplots(figsize=(10,10), facecolor='#F0F0F0')
        plt.tight_layout()
    ax = plt.subplot(subplot)
    ax.set_facecolor('#F8F8F8')
    ax.plot(training)
    ax.plot(validation)
    ax.set_title('model '+ title)
    ax.set_ylabel(title)
    #ax.set_ylim(0.28,1.05)
    ax.set_xlabel('epoch')
    ax.legend(['train', 'valid.'])
#参数要看history里面有什么,好像是history.keys(),反正有key,记不大清楚了
display_training_curves(history.history['loss'], history.history['val_loss'], 'loss', 211)
display_training_curves(history.history['sparse_categorical_accuracy'], history.history['val_sparse_categorical_accuracy'], 'accuracy', 212)

裁剪也是一门艺术

def bbox(img):
    rows = np.any(img, axis=1)
    cols = np.any(img, axis=0)
    rmin, rmax = np.where(rows)[0][[0, -1]]
    cmin, cmax = np.where(cols)[0][[0, -1]]
    return rmin, rmax, cmin, cmax

def crop_resize(df, size=224, pad=16):
    resized = {}
    #crop a box around pixels large than the threshold 
    #some images contain line at the sides
    for i in tqdm(range(df.shape[0])):
        #somehow the original input is inverted
        img0 = 255 - df.loc[df.index[i]].values.reshape(137, 236).astype(np.uint8)
        #normalize each image by its max val
        img0 = (img0*(255.0/img0.max())).astype(np.uint8)
        
#         _, thresh = cv2.threshold(img0,0,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
#         ymin,ymax,xmin,xmax = bbox(thresh[5:-5,5:-5] > 80)
#         #cropping may cut too much, so we need to add it back
#         xmin = xmin - 13 if (xmin > 13) else 0
#         ymin = ymin - 10 if (ymin > 10) else 0
#         xmax = xmax + 13 if (xmax < WIDTH - 13) else WIDTH
#         ymax = ymax + 10 if (ymax < HEIGHT - 10) else HEIGHT
#         img = img0[ymin:ymax,xmin:xmax]
#         #remove lo intensity pixels as noise
#         img[img < 28] = 0
#         lx, ly = xmax-xmin,ymax-ymin
#         l = max(lx,ly) + pad
#         #make sure that the aspect ratio is kept in rescaling
#         img = np.pad(img, [((l-ly)//2,), ((l-lx)//2,)], mode='constant')
        resized_roi = cv2.resize(img0, (size, size),interpolation=cv2.INTER_AREA)
        resized[df.index[i]] = resized_roi.reshape(-1)
    resized = pd.DataFrame(resized).T
    return resized

划分数据集方面sklearn也很强大

x_train, x_test, y_train, y_test = train_test_split(X_train, Y_train,
                                                    test_size=0.1, random_state=42)

也有kfold的,原理差不多,都挺好用

当训练的数据过大时,内存难以一次加载完成就需要del了

del x_train, x_test, y_train, y_test
gc.collect()

gc的库需要单独导入,不然就是表面删除了

  • 2
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

追梦小狂魔

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值