图像回归问题不同于图像分类问题,它要求模型给出的结果是一个连续的预测值,而不是离散的类别。
图像回归问题非常少见,大部分仍然是图像分类问题,但FastAI也可以解决图像回归问题。
1. 准备数据集
此处的数据集来源于:biwi_head_pose,下载后就可以使用。
1.1 自定义换算函数
这个项目的要求是预测出图像中人脸中心点的位置,所以要求模型给出的结果是一个坐标值(x,y),表示人脸中心位于图像的x和y处。数据集给的标注label也位于每张图片对应的txt中。其txt的格式为:eg: frame_00009_pose.txt:
第5行的三个数据表示了人脸中心的位置,这三个数据需要做进一步运算才能换算成中心坐标值。
所以,这个数据集还需要我们自定义一些换算函数。
def convert_biwi(coords):
c1 = coords[0] * cal[0][0]/coords[2] + cal[0][2]
c2 = coords[1] * cal[1][1]/coords[2] + cal[1][2]
return tensor([c2,c1])
def get_ctr(f):
ctr = np.genfromtxt(img2txt_name(f), skip_header=3)
return convert_biwi(ctr)
def get_ip(img,pts): return ImagePoints(FlowField(img.size, pts), scale=True)
上面的换算函数中,convert_biwi可以参考数据集官方给出的换算方法,get_ctr是我们对某一张具体的图像f,找到其label所在的txt,然后读取txt内容,进行换算得到人脸中心的坐标值。标注处该坐标点为:
1.2 组建databunch
由于labels都是中心坐标值,所以此处用PointsItemList,如下:
data = (PointsItemList.from_folder(path)
.split_by_valid_func(lambda o: o.parent.name=='13')
.label_from_func(get_ctr)
.transform(get_transforms(), tfm_y=True, size=(120,160))
.databunch().normalize(imagenet_stats)
)
在创建val set时,考虑到同一个人的脸部相似度非常大,所以用不同的人脸作为val set, 此处用标号为13的人的脸部作为val set,其他人的脸部作为train set。
获取label的方式是get_ctr这个换算函数,这个函数从img的文件名中解析出对应的txt的路径和名称,然后换算得到中心点的坐标值。
此处的size并没有用常见的正方形图片,而是长方形,这个比例和原图的比例一致,为了保持人脸结构不会变形。
2. 模型训练
模型的构建和以前一样,用resnet34作为基本结构,创建cnn_learner即可。
learn = cnn_learner(data, models.resnet34)
在5个epochs的训练之后,结果为:
一般的,对于回归问题,模型的loss function应该采用MSE,在课程中所用的notebook中使用了learn.loss_func = MSELossFlat()
,但此处没有明确指定MSELoss,估计是已经整合到cnn_learner中。
最后,显示下模型预测出来的结果和ground truth,将两者进行对比。
可以看出,预测出来的中心点位置几乎和原来的ground truth位置一致。
网友评论