用神经网络模型给你的照片打分(Part I)

在上一篇《如何通过直方图判断照片的曝光》中,我试图以用户对照片的评分作为评判标准,找出照片直方图与其曝光好坏之间的关系,然而结果并不理想。一方面,曝光水平与最终的评分(点赞用户数量)之间未必相关;另一方面,直方图是对图像整体亮度水平的统计结果,这一粗略的统计损失了很多图像信息(构图、内容)等。此外,上一次收集了评分大于50的1w 张照片,结果发现评分的分布存在较大偏差(实际上有75%以上的照片评分不足20),这也导致训练样本失衡。

为了更好地表征图像信息并,这次采用卷积神经网络对照片评分进行预测。而且这次评分的高低并不绝对代表照片的优劣,而是在人群中真实的评价分数。为了确保数据的完整,这次下载了全部 7.85w 张照片,约20G,虽然在最后训练过程中为了节省时间不一定会全部用上,至少这次不会出现训练样本失衡的问题。同时这次也抓取了 6.97w 张照片的拍摄器材信息(EXIF),因此在开始训练之前,首先对这些数据进行一个描述性的统计分析。

问题

  1. 最流行的相机型号排名;
  2. 不同型号相机拍摄的照片所获得的平均得分;
  3. 不同标签的照片最常使用的相机型号分布;
  4. 照片标签之间的相互关联关系。

首先来看格式化存储的数据格式:

import pandas as pd
cameraDF = pd.read_pickle("cameraInfo.pkl")
cameraDF.head()

Pasted_Image_07_05_2017__2_15_PM.jpg

本文采用 Bokeh 对 Pandas 数据进行可视化:

from bokeh.plotting import figure, show
from bokeh.io import output_notebook
from bokeh.models import HoverTool
output_notebook()

1. 最流行的相机型号 Top10

cameraCount = cameraDF.camera.value_counts().head(10).to_frame('Count')
cameraCount

images_statistical_analysis.jpg

绘制图表:

from bokeh.charts import Bar
from bokeh.charts.attributes import cat
bar = Bar(cameraCount, label=cat(sort=False), values='Count', title="相机型号 Top10", legend=None)
bar.xaxis.axis_label = None
bar.yaxis.axis_label = None
bar.title.align = 'center'
bar.width = 900
bar.tools = []
show(bar)

bokeh_plot.png

可以看出,Canon 和 Nikon 几乎包揽前10,还有一个一骑绝尘的 SONY 微单 ILCE-7RM2。

2. 相机型号所拍照片平均得分

也许在大师手中任何器材都能拍出完美的照片,但是我们还是要看看在人群中,使用不同器材拍出的照片所获得的平均评价:

cameraScores = cameraDF.groupby('camera') \
    .filter(lambda x: len(x) > 500) \
    .groupby('camera')['favs'].mean() \
    .to_frame('M')
cameraScores.head()

IMAGE

绘制图表:

from bokeh.charts.attributes import cat
box = Bar(cameraScores.sort_values('M', ascending=False),
          values='M',
          label=cat(sort=False),
          legend=None,
          title='平均得分')
box.title.align = 'center'
show(box)

bokeh_plot.png

3. 不同标签(类型)照片最常用设备

和器材与评分的关系一样,未必存在更适合特定场景的特定器材,但我们还是可以统计一下看看,对于不同类型照片最常使用的拍摄器材。

TOI = cameraDF.tag.unique()[:10]
tagOfInterest = cameraDF[cameraDF.tag.apply(lambda x: x in TOI)]

tagOfInterest = tagOfInterest.groupby(['tag', 'camera'])\
    .count().reset_index()\
    .sort_values(['tag', 'author'], ascending=False)\
    .groupby('tag').head(3)
tagOfInterest['total'] = tagOfInterest.author

绘制图表:

bokeh_plot (1).png

当然这里的标签并不是相互独立的,也许人像中有相当一部分也是美女照片,至于标签之间的相互关系,我们通过下一个图表来展示。

3. 照片标签之间的关联

为了更好地将照片按照评分进行归类,一个更好的方案是按照不同的标签(类型)进行区分。例如,人像和风光照片的评价标准可能存在较大差异,因此在评分之前可以先进行归类。上面提到,不同标签之间可能存在重叠(例如人像和美女),因此我们再来统计一下照片标签之间的关联。

TagRelationship = [] 
for i in range(len(cameraDF)):
    tag = cameraDF.loc[i, 'tag']
    other_tags = cameraDF.loc[i, 'other_tags']
    if tag in TOI:
        for o_t in other_tags.split("|"):
            if o_t != tag and o_t in TOI:
                TagRelationship.append({'main_tag': tag, 'rel_tag': o_t, 'value': 1})

tagRelSum = TagRelationshipDF.groupby(['main_tag', 'rel_tag'])['value'].sum() \
    .to_frame().reset_index()

from bokeh.charts import Chord
chd = Chord(tagRelSum, source='main_tag', target='rel_tag', value='value')
show(chd)

bokeh_plot (2).png

总结

以上是对照片信息(EXIF)的一个简单统计,从中多多少少可以找到一些我们想要知道问题的答案。接下来就我下载了 20G 的照片真正想要做的————对照片进行评分,数据量不算特别大,但是要训练起来也不会太快,让我们拭目以待。