通过细胞图像的标签对模型性能的影响,为数据设置优先级和权重。
许多机器学习工作的次要阻碍之一是不足标记数据。而标记数据可能会消耗很长的工夫,并且很低廉,因而很多时候尝试应用机器学习办法来解决问题是不合理的。
为了解决这个问题,机器学习畛域呈现了一个叫做被动学习的畛域。被动学习是机器学习中的一种办法,它提供了一个框架,依据模型曾经看到的标记数据对未标记的数据样本进行优先排序。如果想
细胞成像的宰割和分类等技术是一个疾速倒退的畛域钻研。就像在其余机器学习畛域一样,数据的标注是十分低廉的,并且对于数据标注的品质要求也十分的高。针对这一问题,本篇文章介绍一种对红细胞和白细胞图像分类工作的被动学习端到端工作流程。
咱们的指标是将生物学和被动学习的联合,并帮忙其他人应用被动学习办法解决生物学畛域中相似的和更简单的工作。
本篇文次要由三个局部组成:
- 细胞图像预处理——在这里将介绍如何预处理未宰割的血细胞图像。
- 应用 CellProfiler 提取细胞特色——展现如何从生物细胞照片图像中提取形态学特色,以用作机器学习模型的特色。
- 应用被动学习——展现一个模仿应用被动学习和不应用被动学习的比照试验。
细胞图像预处理
咱们将应用在 MIT 许可的血细胞图像数据集(GitHub 和 Kaggle)。每张图片都依据红细胞 (RBC) 和白细胞 (WBC) 分类进行标记。对于这 4 种白细胞 (嗜酸性粒细胞、淋巴细胞、单核细胞和中性粒细胞) 还有附加的标签,但在本文的钻研中没有应用这些标签。
上面是一个来自数据集的全尺寸原始图像的例子:
创立样本 DF
原始数据集蕴含一个 export.py 脚本,它将 XML 正文解析为一个 CSV 表,其中蕴含每个细胞的文件名、细胞类型标签和边界框。
原始脚本没有蕴含 cell_id 列,但咱们要对单个细胞进行分类,所以咱们略微批改了代码,增加了该列并增加了一列包含 image_id 和 cell_id 的 filename 列:
import os, sys, random
import xml.etree.ElementTree as ET
from glob import glob
import pandas as pd
from shutil import copyfile
annotations = 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 += 1
data = 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 os
import pandas as pd
from PIL import Image
def 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_fname
if __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 experiment
import numpy as np
from matplotlib import pyplot as plt
from modAL import ActiveLearner
import pandas as pd
from modAL.uncertainty import uncertainty_sampling
from sklearn import preprocessing
from sklearn.metrics import , average_precision_score
from sklearn.linear_model import LogisticRegression
# upload the cell profiler features for each cell
data = pd.read_csv('Zaretski_Image_All.csv')
# filter platelets
data = data[data['cell_type'] != 'Platelets']
# define the label
target = 'cell_type'
label_encoder = preprocessing.LabelEncoder()
y = label_encoder.fit_transform(data[target])
# take the learning features only
X = data.iloc[:, 5:]
# create training and testing sets
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 对象。在“estimator”字段中,能够插入任何 sklearnAPI 兼容的模型。在 query_strategy ‘ 字段中能够抉择特定的被动学习策略。这里应用“uncertainty_sampling()”。这方面更多的信息请查看 modAL 文档。
将训练数据分成两组。第一个是训练数据,咱们晓得它的标签,会用它来训练模型。第二个是验证数据,尽管标签也是已知的然而咱们伪装不晓得它的标签,并通过模型预测的标签和理论标签进行比拟来评估模型的性能。而后咱们将训练的数据样本数设置成 5。
# the training size that we will start with
base_size = 5
# the 'base' data that will be the training set for our model
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_active = y_train[:base_size]
# the 'new' data that will simulate unlabeled data that we pick a sample from and label it
X_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 epochs
dummy_scores = []
active_scores = []
# number of desired epochs
range_epoch = 298
# running the experiment
for 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