陕西省住房和城乡建设厅综合服务网站,网站架构设计师简历,wordpress电子商务,沈阳seo顾问引言
算算时间#xff0c;有差不多两年多没在打kaggle了#xff0c;自20年最后一场后#xff08;其实之前也就打过两场#xff0c;一场打铁#xff0c;一场表格赛是金是银不太记得#xff0c;当时相当于刺激战场#xff0c;过拟合lb大赛太刺激了#xff0c;各种trick只…引言
算算时间有差不多两年多没在打kaggle了自20年最后一场后其实之前也就打过两场一场打铁一场表格赛是金是银不太记得当时相当于刺激战场过拟合lb大赛太刺激了各种trick只有敢想就敢做但最近发现账号都忘了RSNA开赛那段时期有个群里正好有人说要参加具体啥情况忘了然后我正值年底阳了后又恍恍惚惚参加了一场考试转阴后方觉大梦一场梦醒茶凉当然这只是我现在的说辞从11月发生了太多意料之外的事情我现在也只能用一梦黄粱来搪塞需要做一些事情排解一下新年的迷茫与惆怅于是顺势就加入开整。不过这一整又收获了更多煎熬但也把我过剩的精神内耗挥霍了一部分这不得不说也算另一种buff转移了。关于最后拿到了bronze medal我只能说很遗憾又比较幸运因为整个比赛过程期间我都苦于算力很多想法没有付诸于行动做了Rashaad虽然我并不想。比赛最后几天我将lb中0.52的方案融进了自己的base里然后就没有跑了可能我离我心中的成功就差两张3090或者4080的距离但这距离已经形如沟壑PS其实应该去用云平台的中途也看到几个不错的所以本篇主题算是对之前的一个回忆帖也算一个总结帖。
赛题数据分析
赛题说明为 The goal of this competition is to identify breast cancer. You’ll train your model with screening mammograms obtained from regular screening. Your work improving the automation of detection in screening mammography may enable radiologists to be more accurate and efficient, improving the quality and safety of patient care. It could also help reduce costs and unnecessary medical procedures. 赛题图像数据为
one fold only.
train images :num_patient 9530num_image 43771cancer0 42854 (0.979)cancer1 917 (0.021)
validation images :num_patient 2383num_image 10935cancer0 10694 (0.978)cancer1 241 (0.022)即总共加起来5w多张可视化为
def has_cancer(l):return len(l) 2 or (len(l) 1 and l[0] 1)patient_cancer_map train.groupby(patient_id).cancer.unique().apply(lambda l: has_cancer(l))fig, ax plt.subplots(1,2,figsize(20,5))sns.countplot(patient_cancer_map, palettePaired, axax[0]);
ax[0].set_title(Number of patients with cancer);sns.countplot(train.groupby(patient_id).size(), axax[1])
ax[1].set_title(Number of images per patient)
ax[1].set_xlabel(Number of images)
ax[1].set_ylabel(Counts of patients);我们能得出来的信息为
数据样本是高度不平衡的比例差距接近50:1而在大多数情况下患者的样本数一般为4张但有些患者的picture提供了10张这很奇怪
进一步针对target分析为
biopsy_counts train.groupby(cancer).biopsy.value_counts().unstack().fillna(0)
biopsy_perc biopsy_counts.transpose() / biopsy_counts.sum(axis1)fig, ax plt.subplots(1,2,figsize(20,5))
sns.countplot(train.cancer, paletteReds, axax[0])
ax[0].set_title(Number of images displaying cancer);
sns.heatmap(biopsy_perc.transpose(), axax[1], annotTrue, cmapOranges);这里可以获得的insight为
显示癌症的图像数量非常少。这应该比癌症患者的人数还要少。从活检特征来看我们可以说所有癌症患者都进行了活检。但只有大约3%的没有癌症的图像进行了后续活检。也许我们应该在患者层面上了解一下这一功能。
这也是后续我将介绍的一个trick这里先按下不提。
至于更详细的EDA可以查看public公开的gold medal notebooks以及discussion这里不再详述。
该赛题的评价函数为
pF12pPrecision⋅pRecallpPrecisionpRecallpF_1 2\frac{pPrecision \cdot pRecall}{pPrecisionpRecall}pF12pPrecisionpRecallpPrecision⋅pRecall
其中 pPrecisionpTPpTPpFPpPrecision \frac{pTP}{pTPpFP}pPrecisionpTPpFPpTP pRecallpTPTPFNpRecall \frac{pTP}{TPFN}pRecallTPFNpTP
这就是常说的pf1值了但是在这种高度不平衡类别下用pf1值是有很大波动情况的所以这里也算是一个不稳定的trick好用是真好用但过拟合可能也是真过拟合。介绍完赛题下面是我的一个心路历程。
初期——摇摇乐环节
为什么取这个名字是因为可能相当多人如果不是非常纯小白都算是有自己的一个弹药库的即或多或少看过以及会去找之前的方案然后直接套用就简单过一下数据先用之前方案跑了再说生死有命富贵在天一人得道鸡犬升天。这个时期public是混乱的但也是文艺复兴不管专业不专业先提出自己见解有人觉得不对就deleteemmm。。。
然后我这边也是豪言壮语各路大神各显神通有位老板直接说上efficientb8batchsize为128参数拉大但往往越带有别样激情的被拷打后也是越容易放弃的我的另一个高中生队友直接给了一个large_kernel为
class LargeKernel_debias(nn.Conv2d):def forward(self, input: torch.Tensor):finput input.flatten(0, 1)[:, None]target abs(self.weight)target target / target.sum((-1, -2), True)joined_kernel torch.cat([self.weight, target], 0)reals target.new_zeros([1, 1] [s p * 2 for p, s in zip(self.padding, input.shape[-2:])])reals[[slice(None)] * 2 [slice(p, -p) if p ! 0 else slice(None) for p in self.padding]].fill_(1)output, power torch.nn.functional.conv2d(finput, joined_kernel, paddingself.padding).chunk(2, 1)ratio torch.div(*torch.nn.functional.conv2d(reals, joined_kernel).chunk(2, 1))power_ torch.mul(power, ratio)output torch.sub(output,power_)out output.unflatten(0, input.shape[:2]).flatten(1, 2)return out听说在上一个比赛是好用的但这个比赛因为前期没做好预处理300G数据我这服务器磁盘空间都不够根本处理不了就直接使用public公开的512 * 512的数据集顺带加了个二阶优化器结果就是代码没什么问题数据问题很大一个epochs用我的rtx 5000单卡就三小时一个跑得我惊了直接惊为天人还是改回了adam后续老板机跑得咋样我忘了因为模型就没给我了。
当然中间还发生了很多事情做了很多奇思妙想以及胡思乱想式编码因为我也是两年多没学套路了顺带把没走过的坑再重新走一遍当成一种学习与修炼大雾紧接着就到了新的一年。
baseline前——无序转有序
如果说为什么在队友全躺的时候我连算力都没有但还依然坚持走完全程大概就是有青蛙佬hengck23的方案公开吧从前期到最后他的大部分工作都出于分享式的算是在这个比赛对我影响最大的我也学会了很多在1月的时候发觉不能这样毫无方向实验了于是开始看他的实验记录 上述只是截取的两张表格数据他还分享了很多point of view好的或者不好的以及论文。我也是顺着思路找到了LMFLOSS(论文地址https://arxiv.org/pdf/2212.12741.pdf)以及Global Objectives For PyTorchhttps://github.com/Shlomix/global_objectives_pytorch/其中LMFLoss在paper with code中是没代码的但是它表达的意思很简单就是对focal loss和LDAM做了一个加权我中途在kaggle上找了一个脑部的小数据集上试着调了下参但效果差不多所以就选择了后者。相比于BCEloss这种通用公式在不平衡样本集上PRLoss效果更佳显著。
这里确定了baseline的基本模型为efficient-v2因为够小并且在青蛙佬和前排的discuss上看没有必要用太大的模型依照赛后我现在的理解上看就是小模型针对大图像而大模型针对小图像防止过拟合另外发现了之前读数据的方式是不对的没有使用StratifiedGroupKFold那我做k折交叉反而是无序的这里也是转为有序的一个地方即
train_data[fold] -1
cv StratifiedGroupKFold(n_splitsCFG.n_splits, shuffleCFG.shuffle, random_stateCFG.random_state)for fold, (_, valid_idx) in enumerate(cv.split(Xtrain_data[image_id], ytrain_data[cancer], groupstrain_data[patient_id])):train_data.loc[valid_idx, fold] foldassert train_data.groupby([fold, cancer]).size().sum() train_data.shape[0]仅仅只是加了这一步先对Excel进行了分组就提高了2个十分位是巨大的虽然我的分辨率还是低于1024的但显然让模型学习到了更精确的东西。修改完了两个大方向问题以及一些小方向后重新调参排名也终于变得好看了些可好看的结果就是后续一直被爆倒地不起了。
产生baseline——开始佛系
这时候是过年前夕吧我发现了一个根本问题我没有机器没法跑1024分辨率以上的模型public已经上升到这个高度了虽然不能说明这个分辨率就一定好还看见很多13841536的但至少我已经跑不动了我高中生队友已经转去打NLP了因为没思路没机器我也接近放弃但看到public公开了一个0.47的方案非常的简单连带着train和inference一起公开的这时候我心态就变了从目标银牌转变为了体验比赛过程。
开源的0.47方案非常简单我感觉就是在规则允许的9小时内通过非常多的数据增强以及集成来达到最高这里使用了monai包也是我该场比赛才知道发现非常好用的一个医疗图像包它使用的还是基础的efficientv2但增强代码为
cfg.train_transforms Compose([LoadImaged(keysimage, image_onlyTrue),EnsureChannelFirstd(keysimage),RepeatChanneld(keysimage, repeats3),Transposed(keysimage, indices(0, 2, 1)),Resized(keysimage, spatial_sizecfg.img_size, modebilinear),Lambdad(keysimage, funclambda x: x / 255.0),RandFlipd(keysimage, prob0.5, spatial_axis[1]),]
)cfg.val_transforms Compose([LoadImaged(keysimage, image_onlyTrue),EnsureChannelFirstd(keysimage),RepeatChanneld(keysimage, repeats3),Transposed(keysimage, indices(0, 2, 1)),Resized(keysimage, spatial_sizecfg.img_size, modebilinear),Lambdad(keysimage, funclambda x: x / 255.0),]
)
该参数一度在我做512 * 512训练的时候发现epochs在5个左右就接近巅峰我加入了wandb后观察图像基本验证集的loss也就和train一样在4到5个左右epochs就涨不动了然后大概训练了4折然后做集成
all_fold_preds []
for weights in glob.glob(weights_path ffold*.pth):model timm.create_model(cfg.backbone,pretrainedFalse,num_classescfg.num_classes,drop_ratecfg.drop_rate,drop_path_ratecfg.drop_path_rate,)model torch.nn.DataParallel(model)model.to(cuda)model.load_state_dict(torch.load(weights)[model])model model.modulemodel.eval()torch.set_grad_enabled(False)all_ids []all_preds []for batch in infer_dataloader:# print(batch[image].shape,.....image)inputs batch[image].to(cuda)outputs model(inputs)这个idea给了我很大的启发因为我之前提交线上评估的时候感觉时间都很长让我产生了一种错觉觉得kaggle给的空间太小时间太少。但这波增强下去我发现我错了因为该方案的加速主要用到了Dali根据事后我看discussdali自带的提升让整个过程时间提升了接近30%特别是在比赛截止还有一个月的时候因为有个很吊的nvidia工程师也在这场打并且很长时间的第一他直接针对这个比赛数据集的图像格式对dali进行了再次升级加入了jpeg2000 decode我想说不愧是nvidia为了比赛改了一个版本牛批
中间也尝试了很多其它的方案但发现不如该方案给我的感觉直观主要可扩展性大所以我直接就定为了baseline但跑了一个512 * 512分辨率后发现跟1024的差距是真大啊1024的分数是0.47而我跑512就已经到0.25了。
这时候过年看着漫天烟火我不经陷入了沉思这一思考就到了年后。
baseline后——automl
年后工作忙起来了也有了一些规划颓废感因为没有足够时间精神内耗而少了许多我因为没有机器的原因天天就只是上discuss区看看没有再过多尝试了因为卡在模型训练上发现后续的事情都变得毫无意义有idea但不想付出实践而开始忙于其它事情比如我想开的区块链系列openmmlab训练营以及各种琐碎缠身。
省略中间过程直到前20天nvidia工程师大佬修改了dali版本以及开源了它的SE-ResNeXt50 full GPU decoding方案顺势跑了一波发现效果非常不错该方案中的trick我也觉得非常多比如说一通道升维
class CustomDataset(Dataset):def __init__(self, df, cfg, aug):passdef __getitem__(self, idx):label self.labels[idx]img self.load_one(idx)if self.aug:img self.augment(img)img self.normalize_img(img)torch_img torch.tensor(img).float().permute(2,0,1)feature_dict {input: torch_img,target: torch.tensor(label),}return feature_dictdef __len__(self):return len(self.fns)def load_one(self, idx):path self.data_folder self.fns[idx]try:img cv2.imread(path, cv2.IMREAD_UNCHANGED)shape img.shapeif len(img.shape) 2:img img[:,:,None]except Exception as e:print(e)return img以及gempool
def gem(x, p3, eps1e-6):return F.avg_pool2d(x.clamp(mineps).pow(p), (x.size(-2), x.size(-1))).pow(1.0 / p)class GeM(nn.Module):def __init__(self, p3, eps1e-6, p_trainableFalse):super(GeM, self).__init__()if p_trainable:self.p Parameter(torch.ones(1) * p)else:self.p pself.eps epsdef forward(self, x):ret gem(x, pself.p, epsself.eps)return retdef __repr__(self):return (self.__class__.__name__ f(p{self.p.data.tolist()[0]:.4f},eps{self.eps}))后者这个pooling的对比avg_pool我不知道方案作者是说better具体的在论文中有体现https://arxiv.org/pdf/1711.02512.pdf
我想聊的是前者可能我接触医学图像不多按常理来讲一般都是读成三维三通道图像再去升tensor很少有说直接按一通道来转格式即使在这里它是正确的跟前面的dali和后面的batch一起又将速度提升了。我于是将这个方案嵌入进了我的baseline中但那时候已经是最后几天了简单跑了跑发现比原efficientv2确实有提升并且能集成的模型又多了一个但很可惜最终怠惰了想申请个云平台嫖一波a100还是没有付诸于实践。
所以标题中的automlauto指的是lb我直接不训练了通过嫖公开的model然后加入我之前的调参、预处理和TTA作为了最终成绩事后这时候想想很遗憾很幸运。
公开的各种trick
这节是我赛后看了很多前排的方案感觉可以做一个分类做一个笔记针对我看的这几个我每个方向选一个觉得比较适合我有代表性的。
dataset上
dataset理论上能做的操作就三种一种是删一种是augment一种是直接扩充。这里我考虑没有修改的原因是原数据是dcm格式每个方案修改数据只是针对后续的模型以及还有用metamodel对数据做进一步修改的所以放在后续的model上来讨论。
删减
这个trick其实很容易想到但是想做好比较难根据评价指标是pf1那我们需要删的目标为假阴性但是怎么从这5w张图像中找到基模型分类错误的假阴性呢这里赛后第26th的方案让我有了一种大道至简的感觉。原文为 I realized that all the label tagged for laterality patient_id is the same. That means the label is actually for patient laterality, not image. So the easiest way to deal with this, is to train OOF and drop False Negatives with high confidence( e.g. the label is 1 but model predict probability is like 0.1 or 0.01). The CV score boost huge after this is done( about 0.03 to 0.04 ). 我当初也想了很多方式但其实最简单的方案也是最直接有效的就藏在了train.csv中既然图像方式很难走通为什么不更上一级通过病患呢然后我去看了一下作者公开的github大致找到删的规则为
for patient_id, laterality in itertools.product(train_df.loc[(train_df.cancer 1) (train_df.fold 10)].patient_id.unique(), (0, 1)
):sub_df train_df.loc[(train_df.patient_id patient_id) (train_df.laterality laterality) (train_df.cancer 1)]if sub_df.shape[0] 0:continueto_delete_index sub_df.loc[sub_df.oof_prob tao.args.fp_threshold].indexif len(to_delete_index) sub_df.shape[0]:to_delete_index sub_df.loc[sub_df.oof_prob ! sub_df.oof_prob.max()].indextrain_df.drop(to_delete_index, inplaceTrue)// An highlighted block
var foo bar;作者的github为https://github.com/louis-she/rsna-2022-public
增强
这里的增主要只数据增强而增强方案就太多了这里贴出8th公开的方案
def mixup_augmentation(x:torch.Tensor, yc:torch.Tensor, alpha:float 1.0):Function which performs Mixup augmentationassert alpha 0, Alpha must be greater than 0assert x.shape[0] 1, Need more than 1 sample to apply mixuplam np.random.beta(alpha, alpha)rand_idx torch.randperm(x.shape[0])mixed_x lam * x (1 - lam) * x[rand_idx, :]yc_j, yc_k yc, yc[rand_idx]return mixed_x, yc_j, yc_k, lamdef get_transforms_16bit(data, img_size, normalize_mean, normalize_std):if data train:return Compose([ToFloat(max_value65535.0),RandomResizedCrop(img_size[0], img_size[1], scale(0.8, 1), ratio(0.45, 0.55), p1), HorizontalFlip(p0.5),VerticalFlip(p0.5),ShiftScaleRotate(rotate_limit(-5, 5), p0.3),RandomBrightnessContrast(brightness_limit(-0.1,0.1), contrast_limit(-0.1, 0.1), p0.5),JpegCompression(quality_lower80, quality_upper100, p0.3),Affine(p0.3),ToTensorV2(),])elif data valid:return Compose([ToFloat(max_value65535.0),Resize(img_size[0], img_size[1]),ToTensorV2(),])扩增
即使用外部数据比赛规则并没有禁止但基本要kaggle内公开的吧比如20th的方案 Likewise my timm backbones were pretrained on VinDr by predicting BIRADS. I used CBIS, Vindr PL as external data (boosted my CV by ~0.02). 后面我看到还用了纽约大学的预训练模型但不知道啥原因被kaggle禁止了这里可以去看原discussion主要是VinDr数据集介绍为 FFDM / Full Field Digital Mammography / similar to RSNA dataset5000 patients / 337.8 GB datasetAll 20K images are marked with density classificationFindings annotations with bounding boxes around various types of marked regions. - 241 of these findings are marked BIRADS 5 (very high probability of malignancy) - 995 of the findings are marked BIRADS 4 (about 30% chance of cancer) - Remainder of bbox findings are BIRADS 3, so 2254 images have been annotatedI traded emails with who I reasonably believe is the author of the dataset (Nguyễn Quý Hà), and he said it would be OK to use this data with this RSNA Kaggle competition. Still waiting to hear back from physionet. It goes without saying of course, that you can’t rely on anything I say here as any type of legal guarantee. 看完介绍我就感觉非常适合rsna作者这里说提升了0.02我感觉应该是没有做什么清洗针对负样本以及我上面所提trick清除 false negatives应该还能比0.02高一点。我比赛期间也去找了external data但扩增的是CMMDThe Chinese Mammography Database2022结果发现不太好跟没扩差不多但那是在baseline之前了那时候因为跑一次时间太久对结果没有啥提升的我一般都是不再看了赛后发现这其实很不好玄学了但不能太玄学emmm。
model上
这里除了上述我的baseline中提到的外还包括几个方面吧。
分辨率image size
这个我看到很多用的size闻所未闻比如1536x9601536x768等等我很想学学这些宽高比是怎么搞出来的我猜测可能是根据使用的模型一次次试验从而得到的我确实玩不起。。。
这里顺便补充crop裁剪策略在这个比赛中有非常多的ROI方式比如说66th的非模型方式为 frame_org copy.copy(frame)thres1 np.min(frame)68 #Adjustments were made while viewing the crop image.np.place(frame, frame thres1, 0)thres2 frame_org.sum() / (h*w)vertical_not_zero [True if frame[:,idx].sum() thres2 else False for idx in range(w)]horizontal_not_zero [True if frame[idx,:].sum() thres2 else False for idx in range(h)]crop frame_org[horizontal_not_zero,:]crop crop[:,vertical_not_zero]而再前排的选择了yolo进行crop特别是青蛙佬早早开源了裁剪模型6th的说明是
YOLOX model was trained to generate breast bboxCompared to simple rule-based breast extraction, YOLOX cropped images usually have a smaller region, which seemed to prevent our models from overfittingIn order to shorten inference time, we used simple rule-based crop during inferenceImages were cropped with a random margin during training as augmentationBbox mix (YOLOX crop rule-based crop) were also used as augmentationCropped images are resized to an aspect ratio of 2:1 (1024 x 512 or 1536 x 768)
采样
这里有Negative sampling 和 versampling但这个是个仁者见仁智者见智的idea因为这两种方法都不能保证模型的泛化能力它们只改变了训练集的分布而不是真实的数据分布所以拟合程度需要手动调调这里贴出蛙哥的采样器
class Balancer(torch.utils.data.Sampler):def __init__(self, pos_cases, neg_cases, ratio 3):self.r ratio - 1self.pos_index pos_casesself.neg_index neg_casesself.length self.r * int(np.floor(len(self.neg_index)/self.r))self.ds_len self.length (self.length // self.r)def __iter__(self):pos_index self.pos_indexneg_index self.neg_indexnp.random.shuffle(pos_index)np.random.shuffle(neg_index)neg_index neg_index[:self.length].reshape(-1,self.r)#pos_index np.random.choice(pos_index, self.length//self.r).reshape(-1,1)pos_index_len len(pos_index)pos_index np.tile(pos_index, ((len(neg_index) // pos_index_len) 1, 1))pos_index np.apply_along_axis(np.random.permutation, 1, pos_index)pos_index pos_index.reshape(-1,1)[:len(neg_index)]index np.concatenate([pos_index,neg_index], -1).reshape(-1)return iter(index)def __len__(self):return self.ds_len以及github上一个针对不平衡样本在cifar100上做的实验
Validation error on Long-Tailed CIFAR100
Imbalance2001005020101Baseline64.2160.3855.0948.9343.5229.69Over-sample66.3961.5356.6549.0343.3829.41Focal64.3861.3155.6848.0544.2228.52CB63.7760.4054.6847.4142.0128.39LDAM-DRW61.7357.9652.5447.1441.2928.85BaselineRS59.5955.6551.9145.0941.4529.80WVNRS59.4855.5051.8046.1241.0229.22
链接为https://github.com/feidfoe/AdjustBnd4Imbalance
model策略
这里就各种神仙打架了比如6th的方案 以及4th的stage 1
第一种我没看懂第二种我看懂了但我都大受震撼。但所幸前者提供了源代码到时候去研究一波。其它还有很多牛皮的架构图就不再这里展示了
图像嵌入
我不知道该不该取这个名字主要最近在看cs224w管它直接扯了。这里可以理解成语义分割、背景建模或者图像嵌入具体比如66th的方案
Background noise reduction (kmeans) I apply kmeans-clustering into each image using pixel values, then the pixel values of a cluster which has the lowest summation change into zero. To save time, I used the kmeans-pytorch 以及我看有几个方案提到的原模型
Metamodel - SVM and XGBoost on image enbeddings.
这个很有意思但我暂时没找到开源方案所以去找到一篇论文即
Meta-XGBoost for Hyperspectral Image Classification Using Extended MSER-Guided Morphological Profiles
之后会回过头来再研究一下我还看见一个用xgboost做二折针对前特征做一波多分类即31th的方案 The idea here was to take use of all other information META etc and together with vision model feed features to a XGB model, which is SOTA in handling imbalanced and mix of feature information. We also had information for the negative clas that could be used for smoothing the imbalanced situation, like create more classes. The features for the XGB training and inference where: ‘site_id’,‘laterality’,‘view’,‘age’,‘implant’,‘n_images’,‘image_size’ extracted information from the last dense layer from every model instead of embeddings to minimize the size if the vision information and features to 32 vs 64 features. I created a total of 9 classes from the information in the traindata, “neg”, “pos”, “diffneg”, “rneg”, “negA”, “negB” etc. Data not seen in test data, but it doesn’t matter as you only need to train the XGB to classify them instead which help sort the total information within the negative class region of information, leaving it less imbalanced. 我直接惊为天人我确实没有尝试过很可惜代码也没开源。
Optimizer
这里抛出这个东西主要是最近出lion了看论文说远远超过adamw但该比赛中的一次discussion使用lion的选手好像都没有特别理想很多人说线上掉分了我引出这个只是想在这里Mark一下方便后续回头看。
lion的paper为https://arxiv.org/abs/2302.06675
inference上
这里也有非常多种方式在我看来而赛后很多前排大佬也都用了但好不好用也是一个不稳定的过程比如说中后期热度很高的转tensorrt模型加速但主要都是青蛙佬提出的字节跳动的nextvit但这个模型太复杂了我在复现过程中就发现很慢还有batch操作等等这里不再过多提及因为我后期没事做就是各种琢磨推理了而其实很多都常见方式不能算trick这里唯一一个比较重要的trick就是阈值了。
阈值threshold 这是青蛙哥所做的一张图像我们可以从图中看到因为样本极度不平衡而采取pf1值那么很显然训练一个模型使用多视图输入进行预测结果会比平均值和/或最大值更好即集成。
但还有一种方案更直接就是限制阈值比如最后我是直接写了
# binarize predictions
th np.quantile(sub[cancer_raw].values,0.98)
sub[cancer] (sub[cancer_raw].values th).astype(int)因为统计值是0.97935
df[label].value_counts(normalizeTrue), df[label].value_counts(normalizeFalse), (0.0 0.979351.0 0.02065Name: label, dtype: float64,0.0 233341.0 492Name: label, dtype: int64)当然这里还能根据每折模型的不同预测参数去动态调整阈值即我初始设置一个0.9的threshold然后对模型预测进行一个采样再加上初始值这或许也有比较好的分数。
结尾
该说的都差不多说了这里我只能说过程是曲折的人的心情都在一次次commit上动态调整结果或遗憾或欣喜但最终我只能说不虚此行。