著名人工智能公司Clarifai公司近日推出了识别成人内容的模型和API NSFW,该模型能够很准确地识别含有裸体和半裸的图片和视频,在Clarifai的这篇博文中,作者用裸体检测问题来展示训练现代版的卷积神经网络模型 (convnets) 与过去的研究有何区别。

上周,我们在Clarifai上正式公布了 Not Safe for Work (NSFW) 成人内容识别模型。本周,我们一位数据科学家将带你探索计算机是如何学会分辨裸体人物的。

警告声明:本文内含有用于科研用途的裸体图片。如果你未满十八周岁或者不宜浏览裸体图片,请立即停止阅读。

过去二十年里,裸体图片的自动检测一直是计算机视觉领域的焦点问题,由于其丰富的研究历史和明确的目标,该问题是了解整个领域发展变化的极好例子。在本文中,我将用裸体检测问题来展示训练现代版的卷积神经网络模型 (convnets) 与过去的研究有何区别。

警告:本文内含有未打码的裸体图片,敬请注意!

早在1996年:

此领域的一项开创性工作是Fleck等人完成的一个项目,戏称为“寻找裸体人”。论文在90年代中期发表,它反映了计算机视觉研究者们在使用卷积神经网络之前所做的典型工作。在论文的第二段,他们概括了这种技术:

算法:
— 首先,筛选出含有大量肤色区域的图片;
— 其次,在这些区域内寻找长条状区域,按照人体结构的信息用专用组合器把它们组合成可能的肢体部位,并且连接这些肢体部位。

皮肤检测是通过对色彩空间过滤来实现,组合皮肤区域是通过对人体建模来实现,它将人体建模成“由相邻圆柱体组合而成的物体,每个独立部分的几何形状和各个部分之间的比例都符合人体骨架”(论文第二节)。为了更好地理解实现这类算法的工程技术,我们来看论文的图1,作者展示了一部分他们人为构造的组合规则:


图1. 左图:组合规则(箭头)说明了如何合并简单的组合(如躯干)形成复杂的组合(如四肢和身体的连接)。这些规则受限于它们在2维空间的相对位置,这是由于它们在3维空间有特定的组合分布。虚线表示了还未实现的组合规则。中图:组合器拒绝将大腿和脊椎(虚线表示的是盆骨)组合在一起,因为如果人在这种姿势下大腿会遮盖躯干,使得躯干不容易被检测到。右图:这个臀部连接也被拒绝了。髋骨连接的限制阻止了人的大腿如此摆放。

论文中提到“在138张无限制裸体照片的测试集上,准确率达到了60%,召回率达到52%”。他们还给出了一些真阳性和假阳性的图片例子,并标明算法检测到的相关特征:


图3. 成功检测出裸体人物的典型图片。皮肤过滤器的输出结果如图所示,脊椎用红线表示,肢体连接用蓝线表示,肢体与躯干连接用绿线表示。


图6. 错误地识别出裸体人物的典型对照图片。这些图片含有与皮肤色彩接近的材料(动物皮肤、木材、面包、褪色的墙面)和容易误判为脊椎或者腰带的结构。组合器经常将平行线组合搞混。

人工构造特征的一个主要问题是特征的复杂性受到了研究院的耐心和想象力的限制。在下一节里,我们将会看到如何训练卷积神经网络来完成同样的任务,更精细地表征相同的数据集。

到了2014年:

深度学习研究员不再发明各种规则来表征输入的数据,而是设计网络模型结构和数据集,使得人工智能系统能从数据中直接学到表征的方法。然而,由于深度学习研究员并没有明确指定网络模型该如何处理给定的数据集,新的问题就产生了:我们如何理解卷积神经网络的行为?

理解卷积神经网络模型的操作就需要解释各层网络的特征行为。我们将在本文的余下篇幅中介绍一个NSFW模型的早期版本,从模型顶层反推到原始输入的像素空间。这样能使我们明白原始输入的什么模式能够导致特征空间的某种特定激活(即为何一张图片被标记为“NSFW”)。

遮挡灵敏度

下图是我们在经过裁剪的Lena Soderberg图像上使用NSFW模型,用64×64的平滑窗口,3像素移窗处理而成。

我们把每个窗口覆盖的像素点传入卷积模型,计算每个像素点的平均“NSFW”得分,得到左侧的热度图。当卷积模型发现某一块裁剪的区域都属于皮肤,它就预测为“NSFW”,在图片中Lena身上相应的位置显示出一大片红色区域。生成右侧的热度图时,我们故意遮挡一部分原始图片,输出1减去平均“NSFW”得分之后的差值(即“SFW”得分)。当NSFW得分最高的区域被遮挡时,“SFW”得分随之上升,我们在热度图中看到了颜色更红的区域。下图的两个图片例子分别表示在上述两种实验中传入卷积模型的两类图片示例:

这些遮挡实验的一个优点就是当分类器完全是一个黑盒的情况下照样能够进行实验。下面是调用我们接口复现上述结果的代码片段:

# NSFW occlusion experimentfrom StringIO import StringIOimport matplotlib.pyplot as plt
import numpy as np
from PIL import Image, ImageDraw
import requests
import scipy.sparse as spfrom clarifai.client import ClarifaiApiCLARIFAI_APP_ID = '...'
CLARIFAI_APP_SECRET = '...'
clarifai = ClarifaiApi(app_id=CLARIFAI_APP_ID,app_secret=CLARIFAI_APP_SECRET,base_url='https://api.clarifai.com')def batch_request(imgs, bboxes):"""use the API to tag a batch of occulded images"""assert len(bboxes) < 128#convert to image bytesstringios = []for img in imgs:stringio = StringIO()img.save(stringio, format='JPEG')stringios.append(stringio)#call api and parse responseoutput = []response = clarifai.tag_images(stringios, model='nsfw-v1.0')for result,bbox in zip(response['results'], bboxes):nsfw_idx = result['result']['tag']['classes'].index("sfw")nsfw_score = result['result']['tag']['probs'][nsfw_idx]output.append((nsfw_score, bbox))return outputdef build_bboxes(img, boxsize=72, stride=25):"""Generate all the bboxes used in the experiment"""width = boxsizeheight = boxsizebboxes = []for top in range(0, img.size[1], stride):for left in range(0, img.size[0], stride):bboxes.append((left, top, left+width, top+height))return bboxesdef draw_occulsions(img, bboxes):"""Overlay bboxes on the test image"""images = []for bbox in bboxes:img2 = img.copy()draw = ImageDraw.Draw(img2)draw.rectangle(bbox, fill=True)images.append(img2)return imagesdef alpha_composite(img, heatmap):"""Blend a PIL image and a numpy array corresponding to a heatmap in a nice way"""if img.mode == 'RBG':img.putalpha(100)cmap = plt.get_cmap('jet')rgba_img = cmap(heatmap)rgba_img[:,:,:][:] = 0.7 #alpha overlayrgba_img = Image.fromarray(np.uint8(cmap(heatmap)*255))return Image.blend(img, rgba_img, 0.8)def get_nsfw_occlude_mask(img, boxsize=64, stride=25):"""generate bboxes and occluded images, call the API, blend the results together"""bboxes = build_bboxes(img, boxsize=boxsize, stride=stride)print 'api calls needed:{}'.format(len(bboxes))scored_bboxes = []batch_size = 125for i in range(0, len(bboxes), batch_size):bbox_batch = bboxes[i:i + batch_size]occluded_images = draw_occulsions(img, bbox_batch)results = batch_request(occluded_images, bbox_batch)scored_bboxes.extend(results)heatmap = np.zeros(img.size)sparse_masks = []for idx, (nsfw_score, bbox) in enumerate(scored_bboxes):mask = np.zeros(img.size)mask[bbox[0]:bbox[2], bbox[1]:bbox[3]] = nsfw_score Asp = sp.csr_matrix(mask)sparse_masks.append(Asp)heatmap = heatmap + (mask - heatmap)/(idx+1)    return alpha_composite(img, 80*np.transpose(heatmap)), np.stack(sparse_masks)#Download full Lena image
r = requests.get('https://clarifai-img.s3.amazonaws.com/blog/len_full.jpeg')
stringio = StringIO(r.content)
img = Image.open(stringio, 'r')
img.putalpha(1000)#set boxsize and stride (warning! a low stride will lead to thousands of API calls)
boxsize= 64
stride= 48
blended, masks = get_nsfw_occlude_mask(img, boxsize=boxsize, stride=stride)#viz
blended.show()

尽管这类实验以非常直接的方式呈现了分类器的输出结果,但缺点是输出的结果很模糊。这使得我们不能完全深入了解模型的工作状态以及发现训练过程中的错误。

去卷积网络模型

当我们用指定数据集训练得到一个模型后,往往希望给出一张图片和某个类别,然后想从模型中得到诸如“我们该如何改变这张图片使其看起来更像是属于那个类别的”之类的答案。针对这类问题,我们使用去卷积网络模型(deconvnet),Zeiler和Fergus014年论文的第二节:


下图展示的是我们用去卷积模型对Lena照片的处理结果,显示了我们该如何修饰Lena图片使其更像一张色情图片(作者注:这类使用的去卷积模型需要传入一张正方形的图片 —— 我们将Lena的完整图片填补成合适的尺寸):

Barbara 是Lena的G级(无限制级)版本。根据我们的去卷积模型,我们给她加上红唇后看起来更像PG级(可能不适宜儿童)图片。

这张图片是Ursula Andress 在电影《007之诺博士》中饰演Honey Rider的剧照,2003年被英国调查评选为“银幕上100个性感瞬间”的第一位:

上述实验的一个显著特点就是卷积模型学习到了红唇和肚脐是“NSFW”得分的指标。这似乎意味着我们“SFW”训练数据集中所包含的红唇和肚脐图片还不够。如果我们只是用准确率/召回率和ROC曲线(如下所示 – 测试集大小为428,271)来评价我们的模型,我们永远也无法发现这个问题,因为我们的测试数据集有着同样的缺陷。这里就是训练基于规则的分类器与现代人工智能研究的本质差别之一。相对于重新人工构造特征,我们重新设计训练数据集直到挖掘出更优质的特征。

最后,我们机智地在确定是色情图片的数据集上运行去卷积模型,确保模型学到的特征真的和明显的nsfw所对应:

这里,我们能清楚地看到卷积模型正确地学到了男女生殖器等器官 —— 我们模型应该标识的部位。而且,模型发现的特征远比研究员人工构造的特征更细化和复杂,有助于我们理解使用卷积模型识别NSFW图片的主要提升点。

如果你有兴趣使用卷积模型来过滤NSFW图片,试一试我们主页上的demo并且申请免费的开发者账号。

免费试用

原文:WHAT CONVOLUTIONAL NEURAL NETWORKS LOOK AT WHEN THEY SEE NUDITY
作者:Ryan Compton
译者:赵屹华 审校:刘翔宇
责编:周建丁(zhojd@csdn.net)

延伸阅读:

  • 深度学习新方向:Multimodal CNN实现图像文本匹配
  • 卷积神经网络在自然语言处理的应用
  • 基于Python的卷积神经网络和特征提取

卷积神经网络模型如何辨识裸体图片相关推荐

  1. TensorFlow精进之路(三):两层卷积神经网络模型将MNIST未识别对的图片筛选出来

    1.概述 自从开了专栏<TensorFlow精进之路>关于对TensorFlow的整理思路更加清晰.上两篇讲到Softmax回归模型和两层卷积神经网络模型训练MNIST,虽然使用神经网络能 ...

  2. 图片2分类卷积神经网络模型训练、分类预测案例全过程(2)

    上一篇博客内容讲述了卷积神经网络模型构建.训练以及模型的保存,包括训练样本数据的预处理和喂给网络. 本篇博客内容讲述训练好的模型的应用和实际图片数据的分类预测. 图片2分类卷积神经网络模型训练.分类预 ...

  3. 图片2分类卷积神经网络模型训练、分类预测案例全过程(1)

    图片2分类卷积神经网络模型训练.分类预测案例全过程(1) 前言 (1)尽管目前有关卷积神经网络深度学习的相关材料较多,但深度学习牵涉到数据预处理.模型构建.模型调用等环节,我也是一个初学者,中间有很多 ...

  4. 卷积神经网络模型解读及数学原理 ——翻拍图片识别

    目录 一.需求背景 二.知识储备 1.深度学习 2.卷积神经网络 3.PyTorch框架 4.张量 5.梯度下降法 三.模型解读 1.输入层 2.隐藏层 1)卷积层 2)激活函数 3)池化层 4)流向 ...

  5. 卷积神经网络模型可解释性

    卷积神经网络模型可解释性 缺乏可解释性仍然是在许多应用中采用深层模型的一个关键障碍.在这项工作中,明确地调整了深层模型,这样人类用户可以在很短的时间内完成他们预测背后的过程.具体地说,训练了深度时间序 ...

  6. 卷积神经网络模型解读汇总——LeNet5,AlexNet、ZFNet、VGG16、GoogLeNet和ResNet

      在我的个人博客上一篇博文中分析了卷积神经网络的结构与相关算法,知道了这些基本原理之后.这篇博文主要介绍在卷积神经网络的发展历程中一些经典的网络模型. LeNet5   LeCun等将BP算法应用到 ...

  7. 基于tensorflow的MNIST手写字识别(一)--白话卷积神经网络模型

    一.卷积神经网络模型知识要点卷积卷积 1.卷积 2.池化 3.全连接 4.梯度下降法 5.softmax 本次就是用最简单的方法给大家讲解这些概念,因为具体的各种论文网上都有,连推导都有,所以本文主要 ...

  8. keras卷积处理rgb输入_CNN卷积神经网络模型搭建

    前言 前段时间尝试使用深度学习来识别评测过程中的图片,以减少人力成本.目前是在深度学习框架Keras(后端使用TensorFlow)下搭建了一个CNN卷积神经网络模型,下面就如何搭建一个最简单的数字图 ...

  9. 卷积神经网络数学建模,常见卷积神经网络模型

    卷积神经网络cnn究竟是怎样一步一步工作的 用一个卷积核滑动图片来提取某种特征(比如某个方向的边),然后激活函数用ReLU来压制梯度弥散. 对得到的结果用另一个卷积核继续提取+reLU,然后池化(保留 ...

最新文章

  1. webscoket绑定php uid,Think-Swoole之WebSocket客户端消息解析与使用SocketIO处理用户UID与fd关联...
  2. 文件表单带数据一起提交spring_基于 Spring 实现管道模式的最佳实践
  3. fastreport 旋转90度_水冷必不可少之90度弯头
  4. CCNP精粹系列之二十四--BGP的水平分隔,推荐
  5. python环境变量的配置 alias_配置别名
  6. 升级python以及安装anaconda
  7. Enterprise Library v5.0 -- Data Access Application Block 开发向导(3)
  8. Android服务的通信方式,android客户端与服务器通信的HTTP通信
  9. solr 如何实现精确查询
  10. Java之抽象类(Abstract Class)与抽象方法(Abstract Method)
  11. MyBatis学习(二)使用注解开发、Mybatis 执行流程、一对多多对一的结果集映射
  12. qq浏览器android flash,支持flash游戏 安卓QQ浏览器2.0预览版体验
  13. auc是ROC曲线面积的直观理解
  14. 《Dreamweaver CS6 完全自学教程》笔记 第十五章:使用行为创建网页特效
  15. html标签和css参数
  16. android图片播放器,android案例之图片播放器
  17. Self-Intro.
  18. The Google File System 译文
  19. uboot usb设备驱动
  20. 石油链安全性及盈利模式

热门文章

  1. linux bash Shell脚本经典之Fork炸弹解析:() { :|: };:
  2. HotSpot JVM 垃圾收集原理
  3. mysql 存储过程声明式游标_Mysql 存储过程中使用游标循环读取临时表
  4. 一个网卡设置多个IP作用
  5. Django MTV结构分析
  6. 数据中心布线系统构成及不同规模范例
  7. 30 天精通 RxJS (05): 建立 Observable(一)
  8. postgresql 数据库远程访问
  9. maven 打jar包将配置文件,和lib包打在外面
  10. Network | 802.1x