当前位置: 首页 > 科技观察

分析细胞图像数据的主动学习

时间:2023-03-14 09:44:30 科技观察

通过细胞图像标签对模型性能的影响,为数据设置优先级和权重。许多机器学习任务的主要障碍之一是缺乏标记数据。标记数据可能非常耗时且昂贵,因此很多时候尝试使用机器学习方法来解决问题是不合理的。为了解决这个问题,机器学习领域出现了一个叫做主动学习的领域。主动学习是机器学习中的一种方法,它提供了一个框架,用于根据模型已经看到的标记数据对未标记数据样本进行优先级排序。细胞成像的分割和分类等技术是一个快速发展的研究领域。与机器学习的其他领域一样,数据标注非常昂贵,对数据标注的质量要求也非常高。为了解决这个问题,本文介绍了一种用于红细胞和白细胞图像分类任务的主动学习端到端工作流程。我们的目标是将生物学和主动学习结合起来,帮助其他人使用主动学习方法来解决生物学中类似且更复杂的任务。本文主要由三部分组成:细胞图像预处理——这里将介绍如何对未分割的血细胞图像进行预处理。使用CellProfiler提取细胞特征-展示如何从生物细胞的摄影图像中提取形态学特征以用作机器学习模型的特征。使用主动学习-显示有和没有主动学习的模拟实验。细胞图像预处理我们将使用MIT许可的血细胞图像数据集(GitHub和Kaggle)。每个图像都根据红细胞(RBC)和白细胞(WBC)分类进行标记。这4种类型的白细胞(嗜酸性粒细胞、淋巴细胞、单核细胞和嗜中性粒细胞)还有额外的标签,但这些标签未在本研究中使用。以下是来自数据集的全尺寸原始图像示例:创建示例DF原始数据集包含一个export.py脚本,该脚本将XML注释解析为包含文件名、单元格类型标签和边界框的CSV表。原始脚本不包含cell_id列,但我们想要对单个细胞进行分类,因此我们稍微修改了代码以添加该列并添加包含image_id和cell_id的文件名列:importos,sys,randomimportxml.etree.ElementTree作为ETfromglobimportglobimportpandasasppdfromshutilimportcopyfileannotations=glob('BCCD_Dataset/BCCD/Annotations/*.xml')df=[]forfileinannotations:#filename=file.split('/')[-1].split('.')[0]+'.jpg'#filename=str(cnt)+'.jpg'filename=file.split('\\')[-1]filename=filename.split('.')[0]+'.jpg'row=[]parsedXML=ET.parse(file)cell_id=0fornodeinparsedXML.getroot().iter('object'):blood_cells=node.find('name').textxmin=int(node.find('bndbox/xmin').text)xmax=int(node.find('bndbox/xmax').text)ymin=int(node.find('bndbox/ymin').text)ymax=int(node.find('bndbox/ymax').text)row=[filename,cell_id,blood_cells,xmin,xmax,ymin,ymax]df.append(row)cell_id+=1data=pd.DataFrame(df,columns=['filename','cell_id','cell_type','xmin','xmax','ymin','ymax'])data['image_id']=data['文件ame'].apply(lambdax:int(x[-7:-4]))data[['filename','image_id','cell_id','cell_type','xmin','xmax','ymin','ymax'].to_csv('bccd.csv',index=False)裁剪为了能够处理数据,第一步是根据边界框坐标裁剪全尺寸图像这就产生了很多大大小小的不同的细节图像:裁剪的代码如下:importosimportpandasaspdfromPILimportImagedefcrop_cell(row):"""crop_cell(row)givenapd.Seriesrowofthedataframe,loadrow['filename']用PIL,裁剪到框row['xmin'],row['xmax'],row['ymin'],row['ymax']保存裁剪后的图像,返回裁剪后的文件名"""input_dir='BCCD\JPEGImages'output_dir='BCCD\cropped'#openimageim=Image.open(f"{input_dir}\{row['filename']}")#以像素为单位的图像大小宽度,高度=im。size#设置裁剪图像的点left=row['xmin']bottom=row['ymax']right=row['xmax']top=row['ymin']#裁剪图像im1=im.crop((left,top,right,bottom))cropped_fname=f"BloodImage_{row['image_id']:03d}_{row['cell_id']:02d}.jpg"#在图像查看器中显示图像#im1.show()#保存图片try:im1.save(f"{output_dir}\{cropped_fname}")except:return'errorwhilesavingimage'returncropped_fnameif__name__=="__main__":#loadlabelscsvintoPandasDataFramefilepath="BCCD\dataset2-master\labels.csv"df=pd.read_csv(filepath)#遍历单元格,裁剪每个单元格,将裁剪后的单元格保存到文件dataset_df['cell_filename']=dataset_df.apply(crop_cell,axis=1)以上是us完成所有预处理后,我们现在继续使用CellProfiler提取特征。使用CellProfiler提取细胞特征CellProfiler是一种免费的开源图像分析软件,可自动对大规模细胞图像进行定量测量。CellProfiler还包括一个GUI界面,为了我们的可视化操作,首先下载CellProfiler,如果CellProfiler打不开,可能需要安装VisualC++发布包,具体安装方法参考官网,打开软件,加载图片即可。想要建立一个管道,你可以在CellProfiler的官网上找到它可用的功能列表。大多数功能分为三个主要组:图像处理,对象处理和测量.常用功能如下:图像处理-转灰度:物体物体处理-识别主要物体测量-测量物体强度CellProfiler可以将输出保存为CSV文件或保存在指定的数据库中。这里我们将输出保存为CSV文件,然后将其加载到Python中进行进一步处理。注意:CellProfiler还可以保存和分享您的图像处理过程。主动学习既然我们有了训练所需的数据,我们就可以开始试验使用主动学习策略是否可以用更少的数据标记获得更高的准确率。我们的假设是,使用主动学习可以大大减少细胞分类,通过在任务上训练机器学习模型所需的标记数据量来节省宝贵的时间和精力。主动学习框架在深入研究实验之前,我们想快速介绍一下modAL:modAL是Python的主动学习框架。它提供了SklearnAPI,因此很容易将其集成到代码中。该框架可以轻松地使用不同的主动学习策略。他们的文档也很清楚,所以建议用它来开始你的主动学习项目之一。主动学习与随机学习为了检验假设,我们将进行一项实验,将添加新标记数据的随机二次抽样策略与主动学习策略进行比较。使用一些相同的标记样本开始训练2个逻辑回归估计器。然后将在一个模型中使用随机策略,在第二个模型中使用主动学习策略。我们首先准备实验数据,加载由CellProfiler语言创建的特征。这里过滤掉无色血细胞的血小板,只保留红细胞和白细胞(为了简化问题,减少数据量)。所以现在我们正在尝试解决二元分类问题-RBC与WBC。使用SklearnLabel的labelencoder进行编码,分割数据集进行训练和测试。#为整个实验导入importnumpyasnpfrommatplotlibimportpyplotaspltfrommodALimportActiveLearnerimportpandasaspdfrommodAL.uncertaintyimportuncertainty_samplingfromsklearnimportpreprocessingfromsklearn.metricsimport,average_precision_scorefromsklearn.linear_modelimportLogisticRegression#为每个celldata=pd上传细胞分析器特征.read_csv('Zaretski_Image_All.csv')#filterplateletsdata=data[data['cell_type']!='Platelets']#definethelabeltarget='cell_type'label_encoder=preprocessing.LabelEncoder()y=label_encoder.fit_transform(data[target])#只取学习特征X=data.iloc[:,5:]#创建训练和测试集X_train,X_test,y_train,y_test=train_test_split(X.to_numpy(),y,test_size=0.33,random_state=42)下一步就是创建模型dummy_learner=LogisticRegression()active_learner=ActiveLearner(estimator=LogisticRegression(),query_strategy=uncertainty_sampling())dummy_learner是使用随机策略一个简单的模型,而active_learner是一个使用主动学习策略的模型。为了实例化主动学习模型,我们使用modAL包中的ActiveLearner对象。在“估计器”字段中,可以插入任何与sklearnAPI兼容的模型。可以在query_strategy'字段中选择特定的主动学习策略。这里使用了“uncertainty_sampling()”。有关这方面的更多信息,请参阅modAL文档。将训练数据分成两组。第一个是训练数据,我们知道它的标签,我们将用它来训练模型。其次是验证数据,虽然标签也是已知的,但是我们假装不知道它的标签,通过将模型预测的标签与实际标签进行比较来评估模型的性能。然后我们将训练数据样本的数量设置为5。#我们将以base_size=5开始的训练大小#将成为我们模型训练集的“基础”数据X_train_base_dummy=X_train[:base_size]X_train_base_active=X_train[:base_size]y_train_base_dummy=y_train[:base_size]y_train_base_trainactive[=:base_size]#将模拟未标记数据的“新”数据,我们从中挑选样本并对其进行标记y_train[base_size:]y_train_new_active[=base_y_size我们训练了298个epoch。在每个epoch中,我们会训练这两个模型并选择下一个样本,并根据每个模型的策略选择是否将样本添加到我们的“基础”数据中,并在每个epoch中测试其准确性。因为分类是不平衡的,所以使用平均准确率分数来衡量模型的性能。在随机策略中选择下一个样本只是将下一个样本添加到虚拟数据集的“新”组中,因为数据集已经洗牌了,所以没有必要这样做。对于主动学习,将使用一种称为“查询”的ActiveLearner方法,它采用“新”的未标记数据集,并返回他建议添加到训练“基础”集中的样本的索引。选定的样本将从组中移除,因此一个样本只能被选择一次。#数组沿epochsdummy_scores=[]active_scores=[]#desiredepochsrange_epoch=298#runningtheexperimentforiinrange(range_epoch):#在“基础”数据集上训练模型active_learner.fit(X_train_base_active,y_train_base_active)dummy_learner.fit(X_train_base_dummy,y_train_base_dummy)#评估模型dummy_pred=dummy_learner.predict(X_test)active_pred=active_learner.predict(X_test)#累加scoresdummy_scores.append(average_precision_score(dummy_pred.active_scorestest),y_precision(active_pred,y_test))#pickthenextsampleintherandomstrategyandrandomly#addittothe'base'datasetofthedummylearnerandremoveitfromthe'new'数据集X_train_base_dummy=np.append(X_train_base_dummy,[X_train_new_dummy[0,:]],轴=0)y_train_base_dummy=np.concatenate([y_train_base_dummy,np.array([y_train_new_dummy[0]])],轴=0)X_train_new_dummy=X_train_new_dummy[1:]y_train_new_dummy=y_train_new_dummy[1:]#选择活动策略中的下一个样本query_idx,query_sample=active_learner.query(X_train_new_active)#将索引添加到活动学习器的“基础”数据集中并将其从'新'数据集X_train_base_active=np.append(X_train_base_active,X_train_new_active[query_idx],axis=0)y_train_base_active=np.concatenate([y_train_base_active,y_train_new_active[query_idx],axis=0)X_train_new_active=np.concatenate([X_train_new_active[:query_idx[0]],X_train_new_active[query_idx[0]+1:]],axis=0)y_train_new_active=np.concatenate([y_train_new_active[:query_idx[0]],y_train_new_active[query_idx[0]+1:]],轴=0)结果如下:plt.plot(list(range(range_epoch)),active_scores,label='ActiveLearning')plt.plot(list(range(range_epoch)),dummy_scores,label='Dummy')plt.xlabel('添加样本数')plt.ylabel('平均精度分数')plt.legend(loc='右下')plt.savefig("模式lsrobustnessvsdummy.png",bbox_inches='tight')plt.show()策略还是有很大区别的。可以看出主动学习仅使用25个样本就可以达到0.9分的平均准确率!并且使用随机需要175个样本才能达到相同的准确率!而且采用主动学习策略的模型得分接近0.99,而随机模型的得分停止在0.95左右!如果我们使用所有数据,那么他们的最终得分是同样,但是我们研究的目的是在少量标记数据的前提下进行训练,所以只使用了数据集中的300个随机样本。主动学习是机器学习中的一组方法,根据未标记的数据样本对模型性能的影响来优先排序的解决方案。由于标记数据是一项涉及许多资源(金钱和时间)的任务,因此判断标记哪些样本可以最大化e模型的性能是非常必要的。细胞成像为生物学、医学和药理学领域做出了巨大贡献。以前,分析细胞图像需要宝贵的专业人力资本,但主动学习等技术的出现给医学领域带来了巨大的好处。它为这个需要大量人工标注数据集的领域提供了很好的解决方案。