我有一个项目已经持续了一段时间,在亚利桑那州北部放置追踪相机,看看能不能拍到一些好照片。这还挺好玩的。
问题在于你会得到很多没有意义的照片,这些照片是由移动的植物触发了红外线、附近但未出现在画面中的动物或天气引起的。我们说的是多少照片呢?上次相机拍摄的照片有124,752张,从我开始做这件事以来,相机已经拍摄了接近一百万张照片。
如果我把每一张图片都发送给OpenAI,即使按照所谓的“预估”费用来看,也得花上超过10,000美元。所以问题是如何高效使用OpenAI,同时减少不必要的消耗,但我不想为此创建一个自定义训练的模型。
从历史上看,我使用的是在COCO数据集上训练的较好物体识别模型,这种模型在适当调整容差后能较好地分辨动物和非动物。但是,这些模型只是基于亚利桑那州北部的动物进行训练的,因此你得不到“麋鹿”这样的结果,取而代之的是像“马”这样的多种分类。此外,郊狼可能被误识别为狗或猫。此外,你还会看到许多长颈鹿和相当数量的大象误报,尤其是大象常常被误识别为假阳性。
寻找大象啊
YOLOv8 有50%的概率在这张图片中看到了一头大象。看不见吗?让我来用特写裁剪展示一下那头大象:
哎,那头大象!
所以显而易见的想法是给成千上万含有动物的图片加上标记,训练自己的数据集。但我这个人比较懒,所以手动标记数万张图片似乎不太实际,而支付费用请人通过标签服务来完成这个工作似乎也不符合初衷。我也想看看不同类型的一般性模型如何结合以创建一个高效的识别管道。因此,我能否利用像GPT4-vision这样的通用模型正确识别出动物?
所以给GPT一个完整的图片并让它找出图片中的动物会花费大约每张图片0.11美元,或者对于我那一百万张图片总计超过10,000美元,这在GPT已将图片缩小到1367x768之后。如果使用原始图片并将其分割成小块,让GPT查看图片所有部分的原始分辨率,每张图片的费用将超过2.5美元。所以我不想那样做。将我那一百万张图片上传到OpenAI需要多少钱?
仅限GPT,10000美元以上
所以第一个阶段是如果 YOLO 说它看不到任何东西,那么我不会问 OpenAI 是否能看到什么东西。这确实大大减少了图像的数量,尤其是我对任何非动物的东西都不感兴趣,所以我可以忽略“长凳”,“雨伞”等。但在某些情况下,如在大量图像中识别大象或阴影,它的识别率仍然很高。比如在大片草丛中发现很多大象或在大量图像中发现阴影。现在我可以说“忽略所有大象”,但有时那些看起来像大象的东西其实并不真的是大象,但却很有趣。
YOLO说那是个大象,它不是,但这事儿还挺有意思的
所以在排除壮观的亚利桑那大象群之前,我想试试能否进一步减少这些呼叫,因为它仍然很费钱。
大于500美元
追踪相机倾向于在单次触发时拍摄多张照片(目前先不考虑视频捕捉,不过下一步会处理),然后暂停30秒再拍一组。这让我们可以确定这些组图属于同一只动物或同一群动物。因此,我们可以在一组中寻找最佳潜在匹配的照片。在寻找“最佳匹配”的过程中,另一部分是在平衡YOLO精度得分和匹配大小。它往往会非常自信地识别到许多非常小的“亚利桑那大象”,这些往往紧挨着一只它不太确定的动物。
第一张图片可以认出这一堆东西
20美元
所以该选哪一个呢?这时就是 SAM(Segment Anything) 发挥作用的时候了。我发现有时候匹配的边界框非常大,但当你让SAM分割图像时,它只会找到几根草。然而,当你在一个匹配中使用SAM时,在该边界框内再使用一次时,你可以根据掩膜在图像中所占的百分比来调整精确度的权重。
这实际上并没有帮我省钱,它只是改善了由移动草丛等引起的误报。所以为了省钱,你就会排除那些框框中只占一小部分的匹配。当动物被正确识别时,它们通常会占据框框相当大的部分,而草不会。这仍然意味着我有很多“Arizona Elephants”在外面,但它确实排除了不少。它也大大改善了下一个阶段中的匹配,特别是在查看麋鹿群时,因此你可以提供它最大的匹配。
这就准备好了最后一步,让OpenAI来识别这只动物。现在,OpenAI根据所需覆盖图像的512x512像素方块的数量来收费,所以如果你使用边界框,在其周围添加边距,然后缩小尺寸或使用更大的边距使其适应512x512,你只需支付一次费用。这在处理大图时能省下很多费用。
省钱512x512
我将提示限制为返回10个字符/词元,提示是:
北美洲动物的名字。如果不是动物,就说“不是动物”。如果是动物,就说“动物是”,然后说名字。
现在OpenAI有时会说“对不起,我不能……”之类的,我将其视为错误(如果返回码有效),有时它会尝试提供帮助,比如“动物是山狮,也叫美洲狮”,而我对这些内容也不关心。经过一些字符串过滤后,我们得到动物的答案,然后这被当作“正式”的识别。
所以一个问题是我们有时会得到很多误报,例如,草在安装摄像头后在镜头前生长。所以,我们采用传统的“三次错误就出局”规则,但稍作调整。
用SAM掩膜重新运行YOLO,看看它是否能在该区域找到匹配。一般来说,这样做会导致YOLO出现假阴性结果,因为它没有被训练来识别正确的动物,但它似乎在过滤上表现还算可以。
这不是一只亚利桑那大象(Masked Box Area 用 YOLO 重新检测)
我把这些双重检查失败的文件放到另一个文件夹。迄今为止,这些失败大多是因为相机对新长出的植物进行了大量拍摄。把它们全部放到一个“垃圾”文件夹里,这样可以快速查看。我们称这个文件夹为“垃圾”,因为它包含了不需要的文件,方便我们快速清理不需要的内容。
OpenAI 正确地识别出这是一只郊狼。
所以经过这一切,我们现在有了来自 YOLO 识别出的盒子、来自 SAM 的掩膜区域,以及来自 OpenAI 的视觉模型的动物名称,并且成本远低于使用单一基础模型,而单一基础模型无法提供这些识别和掩膜信息。这给了我们一个非常丰富的数据集,这是任何单一方法都难以生成的,且价格合理。
简化
原来的图片
YOLO 识别出一个框,框住可能的匹配物
然后通过SAM检查一下口罩。
我们为OpenAI的图像在周围添加上下文,并将图像调整为方形以提高成本效益。
终于根据原始图片,我们识别出了这个动物
多模型方法的成本影响
所以最后一步是在不同位置的摄像头上传用该方法,并统计错误识别和漏识别的数量。漏识别是指错误地识别出不存在的动物,或未能识别出存在的动物。错误识别是指误认动物,即把动物识别错误。在这组对比中,我将把“这绝对是错的”匹配情况与“我能理解你的判断”的匹配情况区分开来。
大幅削减成本
发送所有事物到OpenAI的成本节省的对数曲线
这些成本中需要注意的一点是,如果你使用YOLO(You Only Look Once)并将每个单独的匹配发送到OpenAI,实际上可能会增加花费。例如,当你处理成群的麋鹿时,如果使用YOLO来识别每个“对象”,然后调用OpenAI来处理每个对象,实际成本可能会增加。然而,总体而言,这种链式方法,特别是利用上下文分批的方法,帮助将成本减少了99%以上。
这些图像在原始状态下这个差异相当大。
使用对数尺度,因为差距巨大。请注意,仅仅将图像裁剪成所需比例就对成本有很大影响。在使用GPT4-vision时,理解平铺的概念至关重要,因为这很容易导致你浪费大量资金,如果不理解其工作原理。从那里开始,YOLO过滤进一步节省了超过60%的成本,而真正的节省则来自于理解跟踪相机的工作原理及其重复拍摄时所见动物的上下文信息。这在所有因素中对成本影响最大,是成本节省的关键。
这种方法在识别上很少出现假阳性,假阴性的情况也很少出现。然而,在一次特定的运行中,由于有大量的移动草,确实导致了很多不准确的识别。我正在进一步研究的一个问题是那些假阴性(即OpenAI未能识别图像中的动物)的情况。单独测试时,OpenAI通常能正确识别这些假阴性的图像,但在作为更大规模测试的一部分时却失败了。这可能是与OpenAI方面的一些上下文有关,或者仅仅是与该模型的预览版本相关。
可以添加一句简短的过渡句,以增强流畅性和上下文理解。
总体来说,这是一种很好的方法,可以从超过100,000张图片中筛选出少于1%包含动物的有效图片,并较为准确地识别这些动物。从人的工作流程角度看,这种方法把一个极其枯燥的剔除垃圾的工作转变为从这些图片中寻找最佳图像的任务,而且它不需要我使用任何除了预训练的通用模型之外的东西,包括使用未针对我期望看到的动物类型训练的YOLOv8识别器。
看见你,狐狸先生
在探索GPT4-Vision的过程中,我做了一些发现:
YOLO的精度和识别每次运行都保持一致,但对于GPT4-Vision来说情况并非如此。它有两大变化方式,第一种是对于较低分辨率或较小的匹配项,它有时无法识别,但在后续运行中又能识别成功。第二种变化比如美洲狮的情况,它会被正确识别为美洲狮、山狮或美洲豹,但在不同的运行中,对于同一张图片你可能会得到不同的名称,甚至在同一运行中,你对同一只动物也可能得出不同的命名结果。因此,例如,在一次运行中,你可能会有5张美洲狮的照片和10张美洲豹的照片。
最让人头疼的是,它仅仅返回“Animal 是”而没有其他任何内容。
{‘message’: {‘role’: ‘助手’, ‘content’: ‘这是动物吗?’}}
叫我的名字
对于这些,我给它好评,因为它没有说“不是一种动物”,但只返回一个空结果带来了一些需要调试的额外问题,所以我用YOLO标识符标记这些文件,并表明OpenAI失败了。
其中一个摄像头被一只驼鹿撞掉了(它们似乎非常喜欢舔摄像头),所以后续拍的照片都有点歪了,这严重影响了OpenAI识别动物的能力。我可能会改进模型,利用蒙版自动校正照片。当我再次检查几张图片时,实际上,chatGPT在几幅图片中找到了匹配。
有时候这个可能是一头奶牛。
比如这张图片在第一次运行时没有得到回复,但在通过ChatGPT测试时却得到了结果,而且当我单独测试该包的GPT4-vision API时也得到了结果。这种情况可以被归类为“幻觉”,也可能是因为我使用的是模型的测试版而产生的错误,但无论如何,这都是一种失败。几次测试显示这种情况非常不稳定,牛在某些情况下被识别为“没有动物”,但在再次通过ChatGPT检查时却被正确识别。
有速率限制,等等看.
我在处理一个Beta-API接口,所以对此有所预期,但速率限制问题确实频繁出现,所以在每20次调用后增加一些随机等待时间似乎有所帮助。虽然这样会让处理时间变长,但只要它能正常运行,我就不会太在意。
我的一个问题是在使用GPT时设置最大令牌数时,它是否是根据指定的令牌数生成输出,还是先生成内容再进行修剪。如果你担心基础模型的能耗,你希望它直接按照指定的令牌数生成内容,但这可能会有挑战。从这里的输出来看,这一点非常清楚,它是在生成内容后再进行修剪。
这可能是一种啮齿类动物,比如老鼠等。
也就是说,有一个次要过程负责减化,而不是实际的生成过程这一步。
虽然提示明确说明我只想得到名字或“没有动物”,GPT却添加了额外的内容,不仅仅是像啮齿动物的例子那样简单扩展陈述,还加入了诸如这样的短语。
可能是只黑熊
现在那动物是一头牛,但它在远处,而且牛实际上比熊更常造成人类死亡。但是,我并不想要添加“可能”这样的词,提示要求只提供动物名称。这里我可以考虑用LLamas7B模型来提取动物名称。这点需要注意,因为你在为这些额外的内容付费。
“图片模糊,不够清晰”
这张裁剪后的图片确实有些模糊,不过,这值得我们思考的是,GPT以及所有基础模型是如何报告它们的结果的。根据提示,正确的答案应该是“没有动物的身影”。
调试的一个挑战是,一张图片在一次运行中可能失败,但在下一次运行中却成功了,或者在下一次运行中被定义为不同的动物。由于涉及到“一束”图片的部分逻辑,并从中选出“最好的”一张,这使得问题变得复杂,因为我需要从一束图片中选择,对每张图片进行OpenAI识别,然后用这些结果来设置SAM/YOLO权重,以选出“最好”的一张,而在下一次运行时,OpenAI的识别结果可能会有所不同。这也促使我对背景需求有了更深入的了解,我测试了使用SAM掩膜和非掩膜版本,添加了零边界或50%边界,最终发现,在未掩膜的图片上增加10%的边界得到了最稳定的响应。