为了保护和监控海洋环境及生态平衡,大天然保护协会(The Nature Conservancy)邀请Kaggle社区的参赛者们开发可以出机器学习算法,自动分类和识别远洋捕捞船上的摄像头拍摄到的图片中鱼类的品种,例如不一样种类的吞拿鱼和鲨鱼。大天然保护协会一共提供了3777张标注的图片做为训练集,这些图片被分为了8类,其中7类是不一样种类的海鱼,剩余1类则是不含有鱼的图片,每张图片只属于8类中的某一类别。算法
图片中待识别的海鱼所占整张图片的一小部分,这就给识别带来了很大的挑战性。此外,为了衡量算法的有效性,还提供了额外的1000张图片做为测试集,参赛者们须要设计出一种图像识别的算法,尽量地识别出这1000张测试图片属于8类中的哪一类别。Kaggle平台为每个竞赛都提供了一个榜单(Leaderboard),识别的准确率越高的竞赛者在榜单上的排名越靠前。app
split_train_val.pydom
import os import numpy as np import shutil np.random.seed(2016) root_train = 'data\\train_split' root_val = 'data\\val_split' root_total = 'data\\train' FishNames = ['ALB', 'BET', 'DOL', 'LAG', 'NoF', 'OTHER', 'SHARK', 'YFT'] nbr_train_samples = 0 nbr_val_samples = 0 # 训练集所占比例 split_proportion = 0.8 for fish in FishNames: if not os.path.exists(root_train): os.mkdir(root_train) if not os.path.exists(root_val): os.mkdir(root_val) # 创建各个类别的文件夹 if fish not in os.listdir(root_train): os.mkdir(os.path.join(root_train, fish)) # 当前类别全部的图片 total_images = os.listdir(os.path.join(root_total, fish)) # 训练集中图片的数量 nbr_train = int(len(total_images) * split_proportion) # 打乱数据集 np.random.shuffle(total_images) # 划分出训练集 train_images = total_images[:nbr_train] # 划分出测试集 val_images = total_images[nbr_train:] for img in train_images: # 从train文件夹将图片拷贝至train_split文件夹下 source = os.path.join(root_total, fish, img) target = os.path.join(root_train, fish, img) shutil.copy(source, target) nbr_train_samples += 1 if fish not in os.listdir(root_val): os.mkdir(os.path.join(root_val, fish)) for img in val_images: # 从train文件夹将图片拷贝至val_split文件夹下 source = os.path.join(root_total, fish, img) target = os.path.join(root_val, fish, img) shutil.copy(source, target) nbr_val_samples += 1 print('Finish splitting train and val images!') print('# training samples: {}, # val samples: {}'.format(nbr_train_samples, nbr_val_samples))
ImageDataGenerator()是keras.preprocessing.image模块中的图片生成器,同时也能够在batch中对数据进行加强,扩充数据集大小,加强模型的泛化能力。好比进行旋转,变形,归一化等等。机器学习
参数:ide
- rescale: rescaling factor. Defaults to None.If None or 0, no rescaling is applied,otherwise we multiply the data by the value provided
- featurewise_center: Boolean. 对输入的图片每一个通道减去每一个通道对应均值。
- samplewise_center: Boolan. 每张图片减去样本均值, 使得每一个样本均值为0。
- featurewise_std_normalization(): Boolean()
- samplewise_std_normalization(): Boolean()
- zca_epsilon(): Default 12-6
- zca_whitening: Boolean. 去除样本之间的相关性
- rotation_range(): 旋转范围
- width_shift_range(): 水平平移范围
- height_shift_range(): 垂直平移范围
- shear_range(): float, 透视变换的范围
- zoom_range(): 缩放范围
- fill_mode: 填充模式, constant, nearest, reflect
- cval: fill_mode == 'constant'的时候填充值
- horizontal_flip(): 水平反转
- vertical_flip(): 垂直翻转
- preprocessing_function(): user提供的处理函数
- data_format(): channels_first或者channels_last
- validation_split(): 多少数据用于验证集
方法:函数
- apply_transform(x, transform_parameters):根据参数对x进行变换
- fit(x, augment=False, rounds=1, seed=None): 将生成器用于数据x,从数据x中得到样本的统计参数, 只有featurewise_center, featurewise_std_normalization或者zca_whitening为True才须要
- flow(x, y=None, batch_size=32, shuffle=True, sample_weight=None, seed=None, save_to_dir=None, save_prefix='', save_format='png', subset=None) ):按batch_size大小从x,y生成加强数据
- flow_from_directory()从路径生成加强数据,和flow方法相比最大的优势在于不用一次将全部的数据读入内存当中,这样减少内存压力,这样不会发生OOM,血的教训。
- get_random_transform(img_shape, seed=None): 返回包含随机图像变换参数的字典
- random_transform(x, seed=None): 进行随机图像变换, 经过设置seed能够达到同步变换。
- standardize(x): 对x进行归一化
train.py学习
from keras.applications.inception_v3 import InceptionV3 from keras.layers import Flatten, Dense, AveragePooling2D from keras.models import Model from keras.optimizers import RMSprop, SGD from keras.callbacks import ModelCheckpoint from keras.preprocessing.image import ImageDataGenerator # 超参数 learning_rate = 0.0001 img_width = 299 img_height = 299 nbr_train_samples = 3019 nbr_validation_samples = 758 # nbr_epochs = 25 nbr_epochs = 1 batch_size = 32 # 训练集和测试集路径 train_data_dir = 'data\\train_split' val_data_dir = 'data\\val_split' # 类别 FishNames = ['ALB', 'BET', 'DOL', 'LAG', 'NoF', 'OTHER', 'SHARK', 'YFT'] # 加载InceptionV3模型 print('Loading InceptionV3 Weights ...') InceptionV3_notop = InceptionV3(include_top=False, weights='imagenet', input_tensor=None, input_shape=(299, 299, 3)) # Note that the preprocessing of InceptionV3 is: (x / 255 - 0.5) x 2 # 添加平均池化层和Softmax输出层 print('Adding Average Pooling Layer and Softmax Output Layer ...') # Shape: (8, 8, 2048) output = InceptionV3_notop.get_layer(index=-1).output output = AveragePooling2D((8, 8), strides=(8, 8), name='avg_pool')(output) output = Flatten(name='flatten')(output) output = Dense(8, activation='softmax', name='predictions')(output) InceptionV3_model = Model(InceptionV3_notop.input, output) print(InceptionV3_model.summary()) # 使用梯度降低优化模型 optimizer = SGD(lr=learning_rate, momentum=0.9, decay=0.0, nesterov=True) # 模型编译 InceptionV3_model.compile(loss='categorical_crossentropy', optimizer=optimizer, metrics=['accuracy']) # 自动保存最佳模型 best_model_file = "./weights.h5" best_model = ModelCheckpoint(best_model_file, monitor='val_acc', verbose=1, save_best_only=True) # 训练集数据扩增配置 train_datagen = ImageDataGenerator( rescale=1. / 255, shear_range=0.1, zoom_range=0.1, rotation_range=10., width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True) # 验证集数据扩增配置 val_datagen = ImageDataGenerator(rescale=1. / 255) train_generator = train_datagen.flow_from_directory( train_data_dir, target_size=(img_width, img_height), batch_size=batch_size, shuffle=True, classes=FishNames, class_mode='categorical') validation_generator = val_datagen.flow_from_directory( val_data_dir, target_size=(img_width, img_height), batch_size=batch_size, shuffle=True, classes=FishNames, class_mode='categorical') InceptionV3_model.fit_generator( train_generator, samples_per_epoch=nbr_train_samples, nb_epoch=nbr_epochs, validation_data=validation_generator, nb_val_samples=nbr_validation_samples, callbacks=[best_model])
predict.py测试
from keras.models import load_model import os from keras.preprocessing.image import ImageDataGenerator import numpy as np # 超参数 img_width = 299 img_height = 299 batch_size = 32 nbr_test_samples = 1000 # 类别 FishNames = ['ALB', 'BET', 'DOL', 'LAG', 'NoF', 'OTHER', 'SHARK', 'YFT'] # 模型文件路径 weights_path = os.path.join('weights.h5') # 测试集路径 test_data_dir = os.path.join('data/test_stg1/') if not os.path.exists(test_data_dir): os.mkdir(test_data_dir) # 测试集数据生成器 test_datagen = ImageDataGenerator(rescale=1. / 255) test_generator = test_datagen.flow_from_directory( test_data_dir, target_size=(img_width, img_height), batch_size=batch_size, shuffle=False, # Important !!! classes=None, class_mode=None) test_image_list = test_generator.filenames # 加载模型 print('Loading model and weights from training process ...') InceptionV3_model = load_model(weights_path) # 预测 print('Begin to predict for testing data ...') predictions = InceptionV3_model.predict_generator(test_generator, nbr_test_samples) # 保存预测结果 np.savetxt(os.path.join('predictions.txt'), predictions) # 写入提交文件 print('Begin to write submission file ..') f_submit = open(os.path.join('submit.csv'), 'w') f_submit.write('image,ALB,BET,DOL,LAG,NoF,OTHER,SHARK,YFT\n') for i, image_name in enumerate(test_image_list): pred = ['%.6f' % p for p in predictions[i, :]] if i % 100 == 0: print('{} / {}'.format(i, nbr_test_samples)) f_submit.write('%s,%s\n' % (os.path.basename(image_name), ','.join(pred))) f_submit.close() print('Submission file successfully generated!')
predict_average_augmentation.py优化
from keras.models import load_model import os from keras.preprocessing.image import ImageDataGenerator import numpy as np os.environ["CUDA_VISIBLE_DEVICES"] = "0" # 超参数 img_width = 299 img_height = 299 batch_size = 32 nbr_test_samples = 1000 nbr_augmentation = 5 # 类别 FishNames = ['ALB', 'BET', 'DOL', 'LAG', 'NoF', 'OTHER', 'SHARK', 'YFT'] # 模型文件路径 weights_path = os.path.join('weights.h5') # 测试集文件路径 test_data_dir = os.path.join('data/test_stg1/') # 测试集数据生成器 test_datagen = ImageDataGenerator( rescale=1. / 255, shear_range=0.1, zoom_range=0.1, width_shift_range=0.1, height_shift_range=0.1, horizontal_flip=True) # 加载模型 print('Loading model and weights from training process ...') InceptionV3_model = load_model(weights_path) for idx in range(nbr_augmentation): print('{}th augmentation for testing ...'.format(idx)) random_seed = np.random.random_integers(0, 100000) test_generator = test_datagen.flow_from_directory( test_data_dir, target_size=(img_width, img_height), batch_size=batch_size, shuffle=False, # Important !!! seed=random_seed, classes=None, class_mode=None) test_image_list = test_generator.filenames # print('image_list: {}'.format(test_image_list[:10])) print('Begin to predict for testing data ...') if idx == 0: predictions = InceptionV3_model.predict_generator(test_generator, nbr_test_samples) else: predictions += InceptionV3_model.predict_generator(test_generator, nbr_test_samples) # 同一个模型,平均多个测试样例 predictions /= nbr_augmentation # 写入提交文件 print('Begin to write submission file ..') f_submit = open(os.path.join('submit.csv'), 'w') f_submit.write('image,ALB,BET,DOL,LAG,NoF,OTHER,SHARK,YFT\n') for i, image_name in enumerate(test_image_list): pred = ['%.6f' % p for p in predictions[i, :]] if i % 100 == 0: print('{} / {}'.format(i, nbr_test_samples)) f_submit.write('%s,%s\n' % (os.path.basename(image_name), ','.join(pred))) f_submit.close() print('Submission file successfully generated!')