你来画,AI猜
Posted
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了你来画,AI猜相关的知识,希望对你有一定的参考价值。
参考技术AQuick, Draw! 是Google推出的一款很好玩的AI涂鸦游戏,玩家需要在20秒内画出指定内容,例如鸭子、冰箱、苹果等,它的神经网络会实时识别你的涂鸦。
最近Google在kaggle上发布了优化QuickDraw预测识别能力的比赛, Quick, Draw! Doodle Recognition Challenge ,本篇博文就来是分享涂鸦识别的心得。与以往同类比赛不同的是,这次的数据集规模特别庞大,共有340个分类,总计将近5000万个样本!我在r5 6cores CPU + RTX2070 8G GPU + NVME SSD的机器上训练1 epoch就用时18个小时! 这个比赛的算力门槛很高,如果没有足够的人力和算力支持,那再好的模型也出不来。AI的世界也要拼爹。
为了不至于让你被算力劝退,本文提供的 notebook 只取一小部分数据参与训练,你可以根据实际情况调整数据量。github: here
前文说过这个数据集特别庞大,我把每个分类的样本数统计到counts变量,共340个分类,平均每个分类提供了14万6千个训练样本,最少的样本数分类也达到11万,少数几个分类的样本数则超过30万。
这是样本分类不均的数据集,如果不打算训练完所有的样本,可以每个分类只取最多15万个样本。
数据集中重要的字段有countrycode、drawing、recognized,其中最核心字段是drawing,它就是构成图形的所有笔画中点的集合,drawing字段中的数值是这些点的x、y坐标,将同一笔画中所有临近的两个点用直线相连就完成了一笔,所有笔画组合在一起就是一个完整的图形。
draw_cv2()用于decode drawing字段生成image array。这里我读取的是"panda"分类,并生成头12个样本的图形。可以看到,能看出来带有熊猫特征的只有第三排中间两个样本,换句话说,样本中的噪声信号很大。如果你不打算训练所有的样本,建议只选取recognized == True的样本。recognized == False指的是Quickdraw识别不出来的样本,识别不出来的原因有:一、画错了(噪声) 二、画对了但识别不出来,后者是模型的优化目标。如果想要对recognized == False有更直观的体验,建议你到游戏里玩两把。
解码drawing的方式有两种:
除了算力门槛,这个比赛的另一个要点是如何利用dataset中其他信息,如countrycode,一种方法是将它们也和drawing一起编码(encode)进图像中。
上例中的draw_cv2()只用了一个channel来创建图像,并没有用到另外两个channel:
实际上,可以用不同颜色来encode drawing和countrycode,例如不同笔画用不同的颜色,为每个国家指定一种特定颜色等,构建一套可以encode
额外信息的规则可以让模型提取到更多的特征。
这里的draw_cv2用不同的颜色来区分不同的笔画,如果你有兴趣,也可以用特定的颜色来表示某个countrycode或是为不同的国家在图像上添加一些特殊的标记。
我在建模阶段,一般会选择小数据集以加快建模速度,这里每个分类只取1500个样本,共计51万个训练样本,数据集图像大小是128x128。有参赛者建议将大小提升到224x224、256x256可以得到更好的效果,如果你算力、时间充足可以尝试。
我个人是非常推崇transfer learning的,像这类图像识别问题,首选resnet、resnext这些经Imagenet预训练的模型,但因为Quick, Draw!提供了规模庞大的数据,这让重新训练一个模型成为可能。从理论上讲,pretrained models会让模型更快收敛,但如果不考虑数据量和训练时间,目前还没有论断证明transfer learning比training from strach更好。这就好比说,让一个职业跑步运动员转行踢足球,他会比其他人更快成为职业球员,但却不一定比一个从小就花大量时间金钱练习足球的同龄球员要更强,在现实生活中,后者往往强于前者。Kaiming He他们在 Rethinking ImageNet Pre-training 提出了相同的观点。
Mobilenet 是轻量的convnet,它提出一个称为Depthwise Separable Convolution(conv dw)的卷积层,即每个kernel filter只处理一个2维的freature map,而不是一个3维的freature map matrix,这样一来mobilenet的参数不仅少了很多,计算量也大幅简化。
groups=nin ,告诉conv2d()做depth-wise convolution。
我在Mobilenet顶部增加两个全链接层,并添加batchnorm1d和dropout为模型增加正则化。
模型训练过程并不复杂,用 Fastai library 提供的cyclical learning rate来训练,直到过拟合。
本文分享了我参加这个涂鸦识别比赛的一些心得以及starter notebook。算力是这个比赛的根本,除此之外,还要注意避免CPU和硬盘成为拉慢训练速度的短板。
2022-03-09:我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字。 你来猜我选了哪个数字。 如果你猜到正确的数字,就会 赢得游戏 。 如果你猜错了,那么我会告诉你,我选
2022-03-09:我们正在玩一个猜数游戏,游戏规则如下:
我从 1 到 n 之间选择一个数字。
你来猜我选了哪个数字。
如果你猜到正确的数字,就会 赢得游戏 。
如果你猜错了,那么我会告诉你,我选的数字比你的 更大或者更小 ,并且你需要继续猜数。
每当你猜了数字 x 并且猜错了的时候,你需要支付金额为 x 的现金。
如果你花光了钱,就会 输掉游戏 。
给你一个特定的数字 n ,返回能够 确保你获胜 的最小现金数,不管我选择那个数字 。
答案2022-03-09:
容易想到二分法,但二分法是不对的。
递归或动态规划。
只有1个数字的时候,返回0。
只有两个数字的时候,选小的。
大于等于3个数字的时候,每一个都试一下。
代码用golang编写。代码如下:
package main
import "fmt"
func main()
ret := getMoneyAmount2(1000)
fmt.Println(ret)
func getMoneyAmount2(n int) int
dp := make([][]int, n+1)
for i := 0; i < n+1; i++
dp[i] = make([]int, n+1)
for i := 1; i < n; i++
dp[i][i+1] = i
for L := n - 2; L >= 1; L--
for R := L + 2; R <= n; R++
dp[L][R] = getMin(L+dp[L+1][R], R+dp[L][R-1])
for M := L + 1; M < R; M++
dp[L][R] = getMin(dp[L][R], M+getMax(dp[L][M-1], dp[M+1][R]))
return dp[1][n]
func getMax(a, b int) int
if a > b
return a
else
return b
func getMin(a, b int) int
if a < b
return a
else
return b
执行结果如下:
以上是关于你来画,AI猜的主要内容,如果未能解决你的问题,请参考以下文章
2022-03-09:我们正在玩一个猜数游戏,游戏规则如下: 我从 1 到 n 之间选择一个数字。 你来猜我选了哪个数字。 如果你猜到正确的数字,就会 赢得游戏 。 如果你猜错了,那么我会告诉你,我选
AI开发大作战,华为开发者大会HDC.Cloud Codelabs等你来