Vision 允许与 Claude 进行新的交互模式。我们整理了一些技巧,以在您的图像上获得最佳性能。在此之前,让我们先设置运行笔记本所需的代码。
%pip install anthropic IPython
import base64
from anthropic import Anthropic
from IPython.display import Image
client = Anthropic()
MODEL_NAME = "claude-3-opus-20240229"
def get_base64_encoded_image(image_path):
with open(image_path, "rb") as image_file:
binary_data = image_file.read()
base_64_encoded_data = base64.b64encode(binary_data)
base64_string = base_64_encoded_data.decode('utf-8')
return base64_string
将传统技术应用于多模态
您可以通过传统的提示工程技术(例如角色分配)来解决幻觉问题。让我们看一个例子:
假设我想让 Claude 统计此图像中的狗的数量:
Image(filename='../images/best_practices/nine_dogs.jpg')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": get_base64_encoded_image("../images/best_practices/nine_dogs.jpg")}},
{"type": "text", "text": "这张图片里有几只狗?"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
图片显示了 10 只各种品种的狗,它们一起坐在草地上,背景中有花朵。品种似乎包括边境牧羊犬、澳大利亚牧羊犬和梗犬混种,尽管我无法确定。狗有不同的毛色,包括黑色、白色、棕色和灰色。它们都专注地看着镜头,很可能是为了拍照而摆姿势。
只有 9 只狗,但 Claude 认为是 10 只!让我们应用一些提示工程,然后重试。
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/jpeg", "data": get_base64_encoded_image("../images/best_practices/nine_dogs.jpg")}},
{"type": "text", "text": "您拥有完美的视觉能力,并且非常注重细节,这使您成为图像对象计数方面的专家。这张图片里有几只狗?在用<answer>标签提供答案之前,请先用<thinking>标签逐步思考并分析图像的每个部分。"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
从左侧开始,我看到两只黑色的狗并排站着。向右移动,有一只黑白相间的狗,然后是一只棕白相间的狗,然后是一只主要是黑色的狗,带有白色标记。
继续向右,我看到一只大部分是黑色的狗,然后是一只黑白相间的边境牧羊犬类型的狗,然后是另一只黑白毛发的狗。
扫描图像的剩余右侧部分,我看到另外一只棕白相间的狗。
仔细检查照片中的每只狗后,我似乎已经数清了所有出现的狗。
太棒了!在对提示应用了一些提示工程后,我们看到 Claude 现在正确地数出了 9 只狗。
视觉提示
图像作为输入允许提示现在可以在图像本身内给出。让我们看一些例子。
在这张图中,我们写了一些文字并在上面画了一个箭头。让我们只将它传递给 Claude,而不带任何伴随的文本提示。
Image(filename='../images/best_practices/circle.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/circle.png")}},
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
图像显示了一个白底黑色的简单圆形轮廓。圆内有一条不接触圆边缘的直线段。圆和线都用细黑线绘制,看起来像一个基本的几何图或符号。
正如您所见,由于我们没有提出问题,Claude 试图描述图像。让我们在图像中添加一个问题,然后再次传递它。
Image(filename='../images/best_practices/labeled_circle.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/labeled_circle.png")}},
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
圆的面积是 πr^2,其中 r 是圆的半径。问题中说半径是 12,所以面积是 π(12)^2 = 144π 平方单位。
我们也可以突出显示图像的特定部分并询问有关它的问题。
这两个数字的区别是什么?
Image(filename='../images/best_practices/table.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/table.png")}},
{"type": "text", "text": "这两个数字的区别是什么?"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
截至 2023 年 12 月 31 日的十二个月的北美净销售额(352,828 美元)与截至 2022 年 12 月 31 日的净销售额(315,880 美元)之间的差额为 36,948 美元。
少样本示例
添加示例到提示中仍然可以提高视觉任务的准确性。让我们让 Claude 读取速度计的图片。
Image(filename='../images/best_practices/140.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/140.png")}},
{"type": "text", "text": "我开得多快?"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
图像中的速度计显示速度为 140 公里/小时(约合 87 英里/小时)。
Claude 的答案看起来不太对,它认为我们开的是 140 英里/小时而不是 140 公里/小时!让我们再试一次,但这次在提示中添加一些示例。
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/70.png")}},
{"type": "text", "text": "我开得多快?"}
]
},
{
"role": 'assistant',
"content": [
{"type": "text", "text": "您每小时行驶 70 英里。"}
]
},
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/100.png")}},
{"type": "text", "text": "我开得多快?"}
]
},
{
"role": 'assistant',
"content": [
{"type": "text", "text": "您每小时行驶 100 英里。"}
]
},
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/140.png")}},
{"type": "text", "text": "我开得多快?"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list,
temperature=0
)
print(response.content[0].text)
图像中的速度计显示您每小时行驶 140 英里。
太棒了!通过这些示例,Claude 学会了如何读取速度计上的速度。但请注意,图像的少样本提示并不总是有效,但值得在您的用例中尝试。
多个图像作为输入
Claude 还可以在提示中一次接受和处理多个图像!例如,假设您有一张非常大的图像 - 就像一张长收据的图像!我们可以将该图像分成几块,然后将每一块输入到 Claude。
Image(filename='../images/best_practices/receipt1.png')
Image(filename='../images/best_practices/receipt2.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/receipt1.png")}},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/receipt2.png")}},
{"type": "text", "text": "输出餐厅名称和总金额。"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
餐厅名称是 The Breakfast Club,收据上的总金额是 78.86 美元。
示例对象识别
通过图像输入,您可以将其他图像传递给提示,Claude 将使用该信息来回答问题。让我们看一个例子。
假设我们正在尝试识别图像中的裤子类型。我们可以在提示中为 Claude 提供一些不同类型裤子的示例。
Image(filename='../images/best_practices/officer_example.png')
message_list = [
{
"role": 'user',
"content": [
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/wrinkle.png")}},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/officer.png")}},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/chinos.png")}},
{"type": "image", "source": {"type": "base64", "media_type": "image/png", "data": get_base64_encoded_image("../images/best_practices/officer_example.png")}},
{"type": "text", "text": "这些裤子分别是(按顺序)抗皱正装裤、意大利美尔顿警官裤、修身快干斜纹裤。最后一张图中的裤子是什么?"}
]
}
]
response = client.messages.create(
model=MODEL_NAME,
max_tokens=2048,
messages=message_list
)
print(response.content[0].text)
最后一张图显示一个人穿着浅灰色羊毛正装裤或西裤,搭配棕色皮革正装鞋或乐福鞋。根据面料的质地和垂坠感,这似乎是第二张产品图片中展示的意大利美尔顿警官裤。