通过细胞图像的标签对模型性能的影响,为数据设置优先级和权重。
许多机器学习工作的次要阻碍之一是不足标记数据。而标记数据可能会消耗很长的工夫,并且很低廉,因而很多时候尝试应用机器学习办法来解决问题是不合理的。
为了解决这个问题,机器学习畛域呈现了一个叫做被动学习的畛域。被动学习是机器学习中的一种办法,它提供了一个框架,依据模型曾经看到的标记数据对未标记的数据样本进行优先排序。如果想
细胞成像的宰割和分类等技术是一个疾速倒退的畛域钻研。就像在其余机器学习畛域一样,数据的标注是十分低廉的,并且对于数据标注的品质要求也十分的高。针对这一问题,本篇文章介绍一种对红细胞和白细胞图像分类工作的被动学习端到端工作流程。
咱们的指标是将生物学和被动学习的联合,并帮忙其他人应用被动学习办法解决生物学畛域中相似的和更简单的工作。
本篇文次要由三个局部组成:
- 细胞图像预处理——在这里将介绍如何预处理未宰割的血细胞图像。
- 应用CellProfiler提取细胞特色——展现如何从生物细胞照片图像中提取形态学特色,以用作机器学习模型的特色。
- 应用被动学习——展现一个模仿应用被动学习和不应用被动学习的比照试验。
细胞图像预处理
咱们将应用在MIT许可的血细胞图像数据集(GitHub和Kaggle)。每张图片都依据红细胞(RBC)和白细胞(WBC)分类进行标记。对于这4种白细胞(嗜酸性粒细胞、淋巴细胞、单核细胞和中性粒细胞)还有附加的标签,但在本文的钻研中没有应用这些标签。
上面是一个来自数据集的全尺寸原始图像的例子:
创立样本DF
原始数据集蕴含一个export.py脚本,它将XML正文解析为一个CSV表,其中蕴含每个细胞的文件名、细胞类型标签和边界框。
原始脚本没有蕴含cell_id列,但咱们要对单个细胞进行分类,所以咱们略微批改了代码,增加了该列并增加了一列包含image_id和cell_id的filename列:
import os, sys, randomimport xml.etree.ElementTree as ETfrom glob import globimport pandas as pdfrom shutil import copyfileannotations = glob('BCCD_Dataset/BCCD/Annotations/*.xml')df = []for file in annotations: #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 = 0 for node in parsedXML.getroot().iter('object'): blood_cells = node.find('name').text xmin = 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['filename'].apply(lambda x: int(x[-7:-4]))data[['filename', 'image_id', 'cell_id', 'cell_type', 'xmin', 'xmax', 'ymin', 'ymax']].to_csv('bccd.csv', index=False)
裁剪
为了可能解决数据,第一步是依据边界框坐标裁剪全尺寸图像。这就产生了很多大小不一的细胞图像:
裁剪的代码如下:
import osimport pandas as pdfrom PIL import Imagedef crop_cell(row): """ crop_cell(row) given a pd.Series row of the dataframe, load row['filename'] with PIL, crop it to the box row['xmin'], row['xmax'], row['ymin'], row['ymax'] save the cropped image, return cropped filename """ input_dir = 'BCCD\JPEGImages' output_dir = 'BCCD\cropped' # open image im = Image.open(f"{input_dir}\{row['filename']}") # size of the image in pixels width, height = im.size # setting the points for cropped image left = row['xmin'] bottom = row['ymax'] right = row['xmax'] top = row['ymin'] # cropped image im1 = im.crop((left, top, right, bottom)) cropped_fname = f"BloodImage_{row['image_id']:03d}_{row['cell_id']:02d}.jpg" # shows the image in image viewer # im1.show() # save image try: im1.save(f"{output_dir}\{cropped_fname}") except: return 'error while saving image' return cropped_fnameif __name__ == "__main__": # load labels csv into Pandas DataFrame filepath = "BCCD\dataset2-master\labels.csv" df = pd.read_csv(filepath) # iterate through cells, crop each cell, and save cropped cell to file dataset_df['cell_filename'] = dataset_df.apply(crop_cell, axis=1)
以上就是咱们所做的所有预处理操作。当初,咱们持续应用CellProfiler提取特色。
应用CellProfiler提取细胞特色
CellProfiler是一个收费的开源图像剖析软件,能够从大规模细胞图像中主动定量测量。CellProfiler还蕴含一个GUI界面,容许咱们可视化的操作
首先下载CellProfiler,如果CellProfiler无奈关上,则可能须要装置Visual C ++公布包,具体装置形式参考官网。
关上软件就能够加载图像了, 如果想构建管道能够在CellProfiler官网找到其提供的可用的性能列表。大多数性能分为三个次要组:图像处理,指标的解决和测量。
罕用的性能如下:
图像处理 - 转为灰度图:
指标对象解决 - 辨认次要对象
测量 - 测量对象强度
CellProfiler能够将输入为CSV文件或者保留指定数据库中。这里咱们将输入保留为CSV文件,而后将其加载到Python进行进一步解决。
阐明:CellProfiler还能够将你解决图像的流程保留并进行分享。
被动学习
咱们当初曾经有了训练须要的搜有数据,当初能够开始试验应用被动学习策略是否能够通过更少的数据标记取得更高的准确性。咱们的假如是:应用被动学习能够通过大量缩小在细胞分类工作上训练机器学习模型所需的标记数据量来节俭贵重的工夫和精力。
被动学习框架
在深入研究试验之前,咱们心愿对modAL进行疾速介绍:modAL是Python的沉闷学习框架。它提供了Sklearn API,因而能够非常容易的将其集成到代码中。该框架能够轻松地应用不同的被动学习策略。他们的文档也很清晰,所以倡议从它开始你的一个被动学习我的项目。
被动学习与随机学习
为了验证假如,咱们将进行一项试验,将增加新标签数据的随机子抽样策略与被动学习策略进行比拟。开始用一些雷同的标记样本训练2个Logistic回归估计器。而后将在一个模型中应用随机策略,在第二个模型中应用被动学习策略。
咱们首先为试验筹备数据,加载由Cell Profiler创立的特色。这里过滤了无色血细胞的血小板,只保留红和白细胞(将问题简化,并缩小数据量) 。所以当初咱们正在尝试解决二进制分类问题 - RBC与WBC。应用Sklearn Label的label encoder进行编码,并拆分数据集进行训练和测试。
# imports for the whole experimentimport numpy as npfrom matplotlib import pyplot as pltfrom modAL import ActiveLearnerimport pandas as pdfrom modAL.uncertainty import uncertainty_samplingfrom sklearn import preprocessingfrom sklearn.metrics import , average_precision_scorefrom sklearn.linear_model import LogisticRegression# upload the cell profiler features for each celldata = pd.read_csv('Zaretski_Image_All.csv')# filter plateletsdata = data[data['cell_type'] != 'Platelets']# define the labeltarget = 'cell_type'label_encoder = preprocessing.LabelEncoder()y = label_encoder.fit_transform(data[target])# take the learning features onlyX = data.iloc[:, 5:]# create training and testing setsX_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对象。在“estimator”字段中,能够插入任何sklearnAPI兼容的模型。在query_strategy '字段中能够抉择特定的被动学习策略。这里应用“uncertainty_sampling()”。这方面更多的信息请查看modAL文档。
将训练数据分成两组。第一个是训练数据,咱们晓得它的标签,会用它来训练模型。第二个是验证数据,尽管标签也是已知的然而咱们伪装不晓得它的标签,并通过模型预测的标签和理论标签进行比拟来评估模型的性能。而后咱们将训练的数据样本数设置成5。
# the training size that we will start withbase_size = 5# the 'base' data that will be the training set for our modelX_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_active = y_train[:base_size] # the 'new' data that will simulate unlabeled data that we pick a sample from and label itX_train_new_dummy = X_train[base_size:]X_train_new_active = X_train[base_size:]y_train_new_dummy = y_train[base_size:]y_train_new_active = y_train[base_size:]
咱们训练298个epoch,在每个epoch中,将训练这俩个模型和抉择下一个样本,并依据每个模型的策略抉择是否将样本退出到咱们的“根底”数据中,并在每个epoch中测试其准确性。因为分类是不均衡的,所以应用均匀精度评分来掂量模型的性能。
在随机策略中抉择下一个样本,只需将下一个样本增加到虚构数据集的“新”组中,这是因为数据集曾经是打乱的的,因而不须要再进行这个操作。对于被动学习,将应用名为“query”的ActiveLearner办法,该办法获取“新”组的未标记数据,并返回他倡议增加到训练“根底”组的样本索引。被抉择的样本都将从组中删除,因而样本只能被抉择一次。
# arrays to accumulate the scores of each simulation along the epochsdummy_scores = []active_scores = []# number of desired epochsrange_epoch = 298# running the experimentfor i in range(range_epoch): # train the models on the 'base' dataset active_learner.fit(X_train_base_active, y_train_base_active) dummy_learner.fit(X_train_base_dummy, y_train_base_dummy) # evaluate the models dummy_pred = dummy_learner.predict(X_test) active_pred = active_learner.predict(X_test) # accumulate the scores dummy_scores.append(average_precision_score(dummy_pred, y_test)) active_scores.append(average_precision_score(active_pred, y_test)) # pick the next sample in the random strategy and randomly # add it to the 'base' dataset of the dummy learner and remove it from the 'new' dataset X_train_base_dummy = np.append(X_train_base_dummy, [X_train_new_dummy[0, :]], axis=0) y_train_base_dummy = np.concatenate([y_train_base_dummy, np.array([y_train_new_dummy[0]])], axis=0) X_train_new_dummy = X_train_new_dummy[1:] y_train_new_dummy = y_train_new_dummy[1:] # pick next sample in the active strategy query_idx, query_sample = active_learner.query(X_train_new_active) # add the index to the 'base' dataset of the active learner and remove it from the 'new' dataset 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:]], axis=0)
后果如下:
plt.plot(list(range(range_epoch)), active_scores, label='Active Learning')plt.plot(list(range(range_epoch)), dummy_scores, label='Dummy')plt.xlabel('number of added samples')plt.ylabel('average precision score')plt.legend(loc='lower right')plt.savefig("models robustness vs dummy.png", bbox_inches='tight')plt.show()
策略之间的差别还是很大的,能够看到被动学习只应用25个样本就能够达到均匀精度0.9得分!而应用随机的策略则须要175个样本能力达到雷同的精度!
此外被动学习策略的模型的分数靠近0.99,而随机模型的分数在0.95左右进行了!如果咱们应用所有数据,那么它们最终分数是雷同的,然而咱们的钻研目标是在大量标注数据的前提下训练,所以只应用了数据集中的300个随机样本。
总结
本文展现了将被动学习用于细胞成像工作的益处。被动学习是机器学习中的一组办法,可依据其标签对模型性能的影响来优先思考未标记的数据示例的解决方案。因为标记数据是一项波及许多资源(金钱和工夫)的工作,因而判断那些标记那些样本能够最大水平地进步模型的性能是十分必要的。
细胞成像为生物学,医学和药理学畛域做出了巨大贡献。以前剖析细胞图像须要有价值的业余人力资本,然而像被动学习这种技术的呈现为医学畛域这种须要大量人力标注数据集的畛域提供了一个十分好的解决方案。s
本文援用:
- GitHub — Shenggan/BCCD_Dataset: BCCD (Blood Cell Count and Detection) Dataset is a small-scale dataset for blood cells detection.
- Blood Cell Images | Kaggle
- Active Learning in Machine Learning | by Ana Solaguren-Beascoa, PhD | Towards Data Science
- Carpenter, A. E., Jones, T. R., Lamprecht, M. R., Clarke, C., Kang, I. H., Friman, O., … & Sabatini, D. M. (2006).
- CellProfiler: image analysis software for identifying and quantifying cell phenotypes. Genome biology, 7(10), 1–11.
- Stirling, D. R., Swain-Bowden, M. J., Lucas, A. M., Carpenter, A. E., Cimini, B. A., & Goodman, A. (2021).
https://avoid.overfit.cn/post/e920ecde825b4136ae57fbcd325b9097
作者:Adi Nissim, Noam Siegel, Nimrod Berman