VisProg解析:根据自然语言指令解决复杂视觉任务

news2024/7/6 5:46:15

VisProg:根据自然语言指令解决复杂视觉任务

1. 介绍

VisProg 是一种神经符号系统,可以根据自然语言指令解决复杂的组合视觉任务。VisProg 使用 GPT3 的上下文学习能力来生成 Python 程序,然后执行这些程序以获得解决方案和全面且可解释的基本原理。生成的程序的每一行都可以调用几个现成的计算机视觉模型、图像处理例程或Python函数之一来产生可由程序的后续部分使用的中间输出。

相关论文:Paper for VisProg

2. 安装和配置 VisProg

首先,如果你的系统上还没有安装 Conda,请前往 Anaconda 安装适合你的平台的 Conda 工具。

然后,使用以下命令安装和配置 VisProg:

# 克隆 VisProg 仓库
git clone https://github.com/allenai/visprog.git

# 切换到仓库目录
cd visprog

# 创建 conda 环境并安装依赖
conda env create -f environment.yaml

# 激活 VisProg 环境
conda activate visprog

3. 使用VisProg

在VSCODE中打开文件,填入对应的OpenAI密钥
在这里插入图片描述
笔者在测试时Conda环境有相关依赖需要补充安装:
在visprog环境下执行

pip install appdirs
pip install ipywidgets

4. VisProg 解读

VisProg的关键组成部分是一系列名为interpreter的类,这些类在visprog/engine/step_interpreters.py文件中定义。

例如,EvalInterpreter 类解析和执行 ‘EVAL’ 步骤。它首先使用 parse 方法来解析步骤,然后使用 execute 方法来执行该步骤。如果 inspect 参数为 True,execute 方法还会生成描述该步骤的 HTML 字符串。

class EvalInterpreter():
    step_name = 'EVAL'

    def __init__(self):
        print(f'Registering {self.step_name} step')

# 解析步骤
    def parse(self,prog_step):
        parse_result = parse_step(prog_step.prog_str)
        step_name = parse_result['step_name']
        output_var = parse_result['output_var']
        step_input = eval(parse_result['args']['expr'])
        assert(step_name==self.step_name)
        return step_input, output_var

# 生成 HTML 字符串    
    def html(self,eval_expression,step_input,step_output,output_var):
        eval_expression = eval_expression.replace('{','').replace('}','')
        step_name = html_step_name(self.step_name)
        var_name = html_var_name(output_var)
        output = html_output(step_output)
        expr = html_arg_name('expression')
        return f"""<div>{var_name}={step_name}({expr}="{eval_expression}")={step_name}({expr}="{step_input}")={output}</div>"""

# 执行步骤
    def execute(self,prog_step,inspect=False):
        step_input, output_var = self.parse(prog_step)
        prog_state = dict()
        for var_name,var_value in prog_step.state.items():
            if isinstance(var_value,str):
                if var_value in ['yes','no']:
                    prog_state[var_name] = var_value=='yes'
                elif var_value.isdecimal():
                    prog_state[var_name] = var_value
                else:
                    prog_state[var_name] = f"'{var_value}'"
            else:
                prog_state[var_name] = var_value
        
        eval_expression = step_input

        if 'xor' in step_input:
            step_input = step_input.replace('xor','!=')

        step_input = step_input.format(**prog_state)
        step_output = eval(step_input)
        prog_step.state[output_var] = step_output
        if inspect:
            html_str = self.html(eval_expression, step_input, step_output, output_var)
            return step_output, html_str

        return step_output

Breadcrumbsvisprog/engine /step_interpreters.py中的parse_step函数从步骤字符串中解析出步骤名称、输出变量和参数。它使用了 Python 的 tokenize 库来解析步骤字符串。

def parse_step(step_str,partial=False):
    tokens = list(tokenize.generate_tokens(io.StringIO(step_str).readline))
    output_var = tokens[0].string
    step_name = tokens[2].string
    parsed_result = dict(
        output_var=output_var,
        step_name=step_name)
    if partial:
        return parsed_result

    arg_tokens = [token for token in tokens[4:-3] if token.string not in [',','=']]
    num_tokens = len(arg_tokens) // 2
    args = dict()
    for i in range(num_tokens):
        args[arg_tokens[2*i].string] = arg_tokens[2*i+1].string
    parsed_result['args'] = args
    return parsed_result

5. Notebooks 介绍

VisProg 还包含一些 Jupyter 笔记本,用于展示其在不同任务上的应用:

  • notebooks/ok_det.ipynb:这个 notebook 与 “外部知识对象标记(Outside Knowledge Object Tagging)” 相关。它包含了一些用于通过自然语言处理技术对外部知识对象进行标注的代码和示例。

  • notebooks/image_editing.ipynb:这个 notebook 与 “自然语言图像编辑(Natural Language Image Editing)” 相关。它包含了一些用于根据自然语言指令对图像进行编辑和处理的代码和示例。

  • notebooks/nlvr.ipynb:这个 notebook 与 “自然语言视觉推理(Natural Language Visual Reasoning)” 相关。它包含了一些用于处理自然语言与图像之间的推理任务的代码和示例。

  • notebooks/gqa.ipynb:这个 notebook 与 “视觉问答(Visual Question Answering)” 相关。它包含了一些用于处理视觉问答任务的代码和示例。

整体流程梳理

此处以 notebooks/gqa.ipynb为例子,梳理VisProg的程序整体流程:

# 导入必要的库
import os
import sys
from PIL import Image
from IPython.core.display import HTML
from functools import partial

# 添加上级目录到系统路径,使得可以导入在上级目录中的模块
module_path = os.path.abspath(os.path.join('..'))
if module_path not in sys.path:
    sys.path.append(module_path)
    
# 设置OpenAI Key环境变量
%env OPENAI_API_KEY=<Enter you key here> 

# 从自定义模块导入函数和类
from engine.utils import ProgramGenerator, ProgramInterpreter
from prompts.gqa import create_prompt

# 创建ProgramGenerator和ProgramInterpreter实例对象
# 这些对象将被用于,生成程序和解释程序
# partial方法调用create_prompt生成测试用的Prompts,这些prompts作为generator的输入
interpreter = ProgramInterpreter(dataset='gqa')
prompter = partial(create_prompt,method='all')
generator = ProgramGenerator(prompter=prompter)

# 读取一张图片,并将其大小缩放为合适的大小,并转换为 RGB 格式
# 将要进行推理的图像加载到内存中,以便在后续的操作中使用
image = Image.open('../assets/camel1.png')
image.thumbnail((640,640),Image.Resampling.LANCZOS)
init_state = dict(IMAGE=image.convert('RGB'))
image

# 指定自然语言问题/陈述/指令:定义你的自然语言问题、陈述或指令,这将作为输入提供给程序生成器以生成相应的程序
question = "How many people or animals are in the image?"
# 使用程序生成器对象,将指定的问题/陈述/指令作为输入,生成相应的程序。
prog,_ = generator.generate(dict(question=question))
print(prog)
# 利用程序解释器对象,对生成的程序进行解释和执行,返回结果
result, prog_state, html_str = interpreter.execute(prog,init_state,inspect=True)

# 输出程序的结果
result

# 输出HTML字符串
# 将返回的结果以及执行过程的可视化(比如执行追踪)展示出来,以便更好地理解和分析程序的执行情况
# 该做法也是OpenAI Code Interpreter的做法,使用可视化增强程序的可解释性
HTML(html_str)

对于其中出现的ProgramInterpreter.executecreate_promptProgramGenerator.generate进一步解释如下:

visprog/engine/utils.py/ProgramInterpreter

class ProgramInterpreter:
    def __init__(self, dataset='nlvr'):
        """
        初始化 ProgramInterpreter 类的实例。

        参数:
        dataset (str): 一个字符串,用来注册程序步骤的解释器。

        属性:
        step_interpreters (dict): 字典,存储了与每个程序步骤名称对应的解释器。
        """
        # .step_interpreter中包含了各类图像处理的解释器
        self.step_interpreters = register_step_interpreters(dataset)

    def execute_step(self, prog_step, inspect):
        """
        执行一个程序步骤,并返回结果。

        参数:
        prog_step (Program): 需要执行的程序步骤。
        inspect (bool): 是否需要返回可供检查的结果。

        返回值:
        根据 inspect 的值,可能会返回步骤的输出结果,也可能会返回一个包含步骤的输出结果和 HTML 字符串的元组。
        """
        # 解析程序步骤的字符串形式,获取步骤名称
        step_name = parse_step(prog_step.prog_str, partial=True)['step_name']
        print(step_name)
        # 从步骤解释器字典中获取对应的解释器,然后用它执行程序步骤
        return self.step_interpreters[step_name].execute(prog_step, inspect)

    def execute(self, prog, init_state, inspect=False):
        """
        执行一个完整的程序,并返回结果。

        参数:
        prog (str or Program): 需要执行的程序,可以是字符串形式,也可以是 Program 类的实例。
        init_state (dict): 程序的初始状态。
        inspect (bool): 是否需要返回可供检查的结果。

        返回值:
        根据 inspect 的值,可能会返回程序的输出结果和状态,也可能会返回一个包含程序的输出结果、状态和 HTML 字符串的元组。
        """
        # 如果程序是字符串形式,则转化为 Program 类的实例
        if isinstance(prog, str):
            prog = Program(prog, init_state)
        else:
            assert(isinstance(prog, Program))

        # 将程序的每个指令都转化为 Program 类的实例
        prog_steps = [Program(instruction, init_state=prog.state) \
            for instruction in prog.instructions]

        html_str = '<hr>'
        for prog_step in prog_steps:
            if inspect:
                # 如果需要返回可供检查的结果,则执行每个步骤时都返回步骤的输出结果和 HTML 字符串
                step_output, step_html = self.execute_step(prog_step, inspect)
                html_str += step_html + '<hr>'
            else:
                # 否则,只返回步骤的输出结果
                step_output = self.execute_step(prog_step, inspect)

        # 返回程序的结果
        if inspect:
            return step_output, prog.state, html_str

        return step_output, prog.state

visprog/engine/utils.py/ProgramGenerator

class ProgramGenerator():
    def __init__(self, prompter, temperature=0.7, top_p=0.5, prob_agg='mean'):
        """
        初始化 ProgramGenerator 类的实例。

        参数:
        prompter (function): 函数,用于生成 prompt。
        temperature (float): 控制生成的文本的随机性的参数,值越高,结果越随机。
        top_p (float): 控制生成的文本的多样性的参数,值越高,结果越多样。
        prob_agg (str): 用于计算输出文本概率的聚合函数,可以是 'mean' 或 'sum'。

        属性:
        prompter (function): 存储输入的 prompter。
        temperature (float): 存储输入的 temperature。
        top_p (float): 存储输入的 top_p。
        prob_agg (str): 存储输入的 prob_agg。
        """
        openai.api_key = os.getenv("OPENAI_API_KEY")
        self.prompter = prompter
        self.temperature = temperature
        self.top_p = top_p
        self.prob_agg = prob_agg

    def compute_prob(self, response):
        """
        计算生成的文本的概率。

        参数:
        response (openai.completion_v1.Completion): OpenAI API 返回的响应。

        返回值:
        float: 生成的文本的概率。
        """
        eos = ''
        for i, token in enumerate(response.choices[0]['logprobs']['tokens']):
            if token == eos:
                break

        if self.prob_agg == 'mean':
            agg_fn = np.mean
        elif self.prob_agg == 'sum':
            agg_fn = np.sum
        else:
            raise NotImplementedError

        return np.exp(agg_fn(response.choices[0]['logprobs']['token_logprobs'][:i]))

    def generate(self, inputs):
        """
        根据输入生成一个程序。

        参数:
        inputs (dict): 字典,包含了生成 prompt 所需的输入信息。

        返回值:
        tuple: 包含生成的程序和程序的概率的元组。
        """
        response = openai.Completion.create(
            model="text-davinci-003",
            prompt=self.prompter(inputs),
            temperature=self.temperature,
            max_tokens=512,
            top_p=self.top_p,
            frequency_penalty=0,
            presence_penalty=0,
            n=1,
            logprobs=1
        )

        prob = self.compute_prob(response)
        prog = response.choices[0]['text'].lstrip('\n').rstrip('\n')
        return prog, prob

visprog/prompts/gqa.py/create_prompt

def create_prompt(inputs, num_prompts=8, method='random', seed=42, group=0):
    """
    创建一个提示字符串,该字符串包含一个问题和一些之前生成的程序示例。

    参数:
    inputs (dict): 一个字典,包含需要插入到提示中的值。它应该有一个名为'question'的键,对应的值将被插入到提示的最后一个问题中。
    num_prompts (int, 可选): 如果 method='random',这个参数决定了选择多少个随机的程序示例来构成提示。默认值为8。
    method (str, 可选): 选择程序示例的方法。如果为'random',将会随机选择;如果为'all',将使用所有程序示例。默认值为'random'。
    seed (int, 可选): 用于随机数生成器的种子,以便于复现。默认值为42。
    group (int, 可选): 未使用的参数,保留给可能的未来扩展。默认值为0。

    返回值:
    str: 生成的提示字符串,它包含一些程序示例,然后是一个问题,最后是"Program:",表明下一部分应该是一个程序。
    """
    if method == 'all':
        # 如果方法为 'all',则选择所有的程序示例
        prompt_examples = GQA_CURATED_EXAMPLES
    elif method == 'random':
        # 如果方法为 'random',则随机选择一些程序示例
        random.seed(seed)  # 设置随机数生成器的种子,以便复现
        prompt_examples = random.sample(GQA_CURATED_EXAMPLES, num_prompts)  # 随机选择 num_prompts 个程序示例
    else:
        # 如果 method 不是 'all' 或 'random',则抛出错误
        raise NotImplementedError

    # 将选择的程序示例合并为一个字符串,每个示例之间用换行符分隔
    prompt_examples = '\n'.join(prompt_examples)

    # 在前面添加一些指示性的文字
    prompt_examples = f'Think step by step to answer the question.\n\n{prompt_examples}'

    # 在最后添加问题和 "Program:"
    return prompt_examples + "\nQuestion: {question}\nProgram:".format(**inputs)

6. 结论

本文主要介绍了VisProg,这是一种神经符号系统,可以根据自然语言指令解决复杂的组合视觉任务。VisProg利用GPT3的上下文学习能力生成Python程序,通过执行这些程序来找到解决方案,并提供全面且可解释的解答。

安装和配置VisProg主要涉及克隆VisProg仓库,创建和激活Conda环境,并安装相关依赖。

VisProg的主要组件是一系列名为interpreter的类,这些类定义在visprog/engine/step_interpreters.py文件中。每个类都有解析和执行步骤的方法,如果inspect参数为True,execute方法还会生成描述该步骤的HTML字符串。

VisProg还提供了一些Jupyter笔记本,展示了在不同任务上的应用,包括外部知识对象标记、自然语言图像编辑、自然语言视觉推理和视觉问答等任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/743326.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端学习——css盒子模型、css3新特性、伪类、布局0711TODO

样式还是得具体使用才能理解&#xff0c;不然会忘记也理解不透彻&#xff1b;还有定位&#xff0c;元素溢出&#xff0c;浮动&#xff0c;布局水平&垂直对齐&#xff1a; css3新特性 1过渡 2 动画 3 2D、3D转换 伪类 三种定位方式 弹性布局/栅格布局

VS+QT+OpenCV+C++多线程多摄像头视频监控采集窗体

程序示例精选 VSQTOpenCV多线程多摄像头视频监控采集窗体 如需安装运行环境或远程调试&#xff0c;见文章底部个人QQ名片&#xff0c;由专业技术人员远程协助&#xff01; 前言 这篇博客针对<<VSQTOpenCV多线程多摄像头视频监控采集窗体>>编写代码&#xff0c;代码…

【Matlab】智能优化算法_算数优化算法AOA

【Matlab】智能优化算法_算数优化算法AOA 1.背景介绍2.数学模型2.1 初始化阶段2.2 勘探阶段2.3 开采阶段 3.文件结构4.伪代码5.详细代码及注释5.1 AOA.m5.2 func_plot.m5.3 Get_F.m5.4 initialization.m5.5 main.m 6.运行结果7.参考文献 1.背景介绍 算术是数论的基本组成部分&a…

MySQL的表操作DML,DDL

建表 mysql> create table work(-> dept_id int(11) not null comment 部门号,-> staff_id int(11) not null comment 职工号,-> work_time date not null comment 工作时间,-> wage float(8.2) not null comment 工资,-> poli_face varchar(20) not null …

软考A计划-系统集成项目管理工程师-项目成本管理-中

点击跳转专栏>Unity3D特效百例点击跳转专栏>案例项目实战源码点击跳转专栏>游戏脚本-辅助自动化点击跳转专栏>Android控件全解手册点击跳转专栏>Scratch编程案例点击跳转>软考全系列 &#x1f449;关于作者 专注于Android/Unity和各种游戏开发技巧&#xff…

如何在本地组策略编辑器中启用或禁用剪贴板历史记录

复制粘贴是我们大家都会做的事情,可能一天要做多次。但是,如果你需要一次又一次地复制同样的几件事,你该怎么办?如何在设备上复制内容? 从Windows 10版本17666开始,微软正在解决这一问题,并将剪贴板提升到一个新的水平,只需按下Win+V,你将获得全新的剪贴板体验。 你…

session共享问题和其他常见问题及解决方案

目录 1.shirospringboot中session的共享问题 1.1 如何解决session共享问题 2. 解决前端不支持cookie的效果 2.1.如何把sessionId放入请求头 2.2.重写DefaultWebSessionManager的方法 3.设置前端前置路由守卫 4.如何防止恶意重复登录 5.退出 6.获取当前登录用户的信息 …

jQuery根据数据动态创建表格:列固定,行超出滚动条,绑定td点击事件等

示例如图&#xff0c;代码如下: html: <div class"layui-row" id"avTableulL"><ul></ul></div><div id"avTableulR"><div id"avTableulT"><ul></ul></div><div id"avT…

【华为认证】HCIP-Datacom 2023最新题库

正在备考华为认证的小伙伴应该知道&#xff0c;除了理论知识外&#xff0c;刷题也相当重要&#xff0c;周工这里有一份HCIAHCIP-Datacom带解析的最新题库 点赞留言 即可领取。 1. &#xff08;多选题&#xff09;ISIS的Hello报文主要分为哪几种类型? A.P2P LAN IIH B.…

UnityVR--机械臂场景12-简单流水线应用4

目录 一. 手爪 二. 红外线传感器 三. 工件生成器 四. 总结 上一篇已经实现了机械臂各种动作的控制&#xff0c;本篇实现一下其余的组成部分&#xff0c;比如手爪、传感器和自动放置工件等。 一. 手爪 手爪的模型调整就不多说了&#xff0c;需要设置的是Rigidbody、Collide…

在Visual Studio Code里导出8266固件

1.编辑 .vscode目录下 arduion.json 添加 一个配置项output即输出目录.当然你不设置其它软固件一样会生成,只是就不知道你能不能找到了.我的配置如下 当然这个路径你想写什么 就是什么 . 2. 切换到 arduion的项目文件 xxxx.ino.点击vsc右上的验证 即可在上面设置的目录下找到…

Nginx系列之 一 入门

目录 一、Nginx概述 二、yum安装 三、nginx.conf配置文件详解 3.1 全局块 3.2 events 块 3.3 HTTP 块 四、Nginx 常用命令 五、Nginx代理 4.1 正向代理 4.2 反向代理 六、Nginx的Master-Worker模式 6.1 Master进程的作用是&#xff1f; 6.2 Worker进程的作用是&am…

Layui动态树详解

Layui动态树详解 一、什么是动态树形&#xff1f;二、Layui动态树形基本使用三、动态加载数据4.案列1.实体类2.dao方法3.子实现类4.jsp页面 前言 在前端开发过程中&#xff0c;树形控件是比较常用的控件之一。而Layui框架中&#xff0c;也提供了基于jQuery的树形控件。除了普通…

小程序接口返回errno: 600009 errMsg: “request:fail invalid url “异常问题排查修复记录

小程序封装wxrequest更换域名baseurl后调用接口返回errMsg: "request:fail invalid url "&#xff0c;errno: 600009 控制台输出request的url也是正常的&#xff0c;起初怀疑是没配置域名白名单&#xff0c;但是小程序模拟器勾选了不校验合法域名的&#xff0c;而且…

PWM技术在嵌入式设备运行中的调节应用

PWM&#xff08;脉宽调制&#xff09;是一种通过改变信号的脉冲宽度来控制电压或电流的技术。PWM的等效电压是指将PWM信号转换为相应的直流电压或电流的数值。 在PWM信号中&#xff0c;占空比表示高电平和低电平脉冲宽度的比例。例如&#xff0c;一个占空比为50%的PWM信号意味…

ApiPost - 踩坑指南

1.应用场景 主要用于记录apipost遇到的坑, 以及为遇到的开发者提供参考. 2.学习/操作 1.文档阅读 chatgpt & 其他资料 ApiPost问答-localhost的坑的问题列表 localhost 不能正确解析为本机-ApiPost使用-ApiPost问答 断网了&#xff0c;还能ping通 127.0.0.1 吗&#xff1…

基于STM32的智能花盆系统设计与实现(华为云IOT)

一、设计需求 1.1 设计需求总结 伴随着人们生活水平以及现在科学技术的急速发展,越来越多的人喜欢在家庭栽培一些盆栽植物。可是当代生活节奏过快,导致盆栽大多数都不能得到很好的补充水分和阳光照射,从而导致盆栽的生活周期变短。如何利用现代电子技术设计一种可自动浇水…

Android Java代码与JNI交互 JNI访问Java类方法 (七)

🔥 Android Studio 版本 🔥 🔥 创建包含JNI的类 JNIAccessMethod.java 🔥 package com.cmake.ndk1.jni;import com.cmake.ndk1.model.Animal;public class JNIAccessMethod {static {System.loadLibrary("access-method-lib");}public native void access…

Spring Bean生命周期以及PostProcessor后置处理器

简介 所谓Bean的生命周期&#xff0c;就是一个 Bean 从创建到销毁&#xff0c;所经历的各种方法调用。 一个Bean的生命周期分为四个阶段&#xff1a; 实例化(Instantiation)&#xff1a;Spring容器负责创建Bean的实例&#xff0c;可以通过构造方法或者无参构造方法进行实例化…

电脑应用程序发生异常怎么办?

有时候我们打开电脑上面的某个软件时&#xff0c;会打不开&#xff0c;并且会弹出如下的错误提示“应用程序发生异常 未知的软件异常&#xff08;&#xff58;&#xff58;&#xff58;&#xff09;&#xff0c;位置为&#xff58;&#xff58;”。相信大多数的人在使用电脑的时…