使用 watsonx.ai 和 IBM Granite 构建 AI 造型师

在本教程中,您将了解如何打造由生成式 AI 驱动的个人造型师。本教程利用 IBM® Granite Vision 3.2 大语言模型处理图像输入,并利用 Granite 3.2最新的增强推理能力生成可定制的服装搭配创意。

简介

您是否经常在想这样的问题:“我今天穿什么?面对满柜的衣服,我甚至不知道从何下手!”我们很多人都面临着同样的困扰。借助前沿的人工智能 (AI) 模型,这个难题可以迎刃而解。

AI 造型:工作原理

我们的 AI 驱动解决方案由以下阶段组成:

  1. 用户上传现有衣橱中的服饰图片,甚至愿望清单中单品图片,一次一件。
  2. 用户选择以下条件:
  • 场合:休闲或正式。
  • 时间:上午、下午或晚上。
  • 季节:春、夏、秋或冬。
  • 地点(例如,咖啡店)。

3. 提交输入后,多模态 Granite Vision 3.2 模型会遍历图片列表,并返回以下输出:

  • 单品描述。
  • 类别:衬衫、裤子或鞋子。
  • 场合:休闲或正式。

4. 具备增强推理能力的 Granite 3.2 模型此时便化身为一名时尚造型师。LLM 利用 Vision 模型的输出来提供适合用户特定场合的穿搭建议。

5. 装备建议、用户上传的物品数据框和所述个性化推荐中的图片都会返回给用户。

先决条件

您需要一个 IBM® Cloud 帐户才能创建 watsonx.ai™项目。

步骤

要使用 watsonx 应用程序编程接口 (API),您需要完成以下步骤。注意,您也可以在 GitHub 上访问本教程。 

第 1 步:设置环境

  1. 使用您的 IBM Cloud 帐户登录 watsonx.ai

  2. 创建一个 watsonx.ai 项目

    您可以从项目内部获取项目 ID。点击管理选项卡。然后,从常规页面的详细信息部分复制项目 ID。您需要此 ID 来完成本教程。

第 2 步:设置 watsonx.ai 运行时服务和 API 密钥

  1. 创建 watsonx.ai 运行时服务实例(选择 Lite 计划,这是一个免费实例)。

  2. 生成 API 密钥

  3. 将 watsonx.ai 运行时服务与您在 watsonx.ai 中创建的项目关联。 

第 3 步:克隆存储库(可选)

为了在使用此 AI 工具时获得更具交互性的体验,请克隆 GitHub 存储库,并按照 AI 造型师项目中的 README.md 文件中的设置说明,在本地计算机上启动 Streamlit 应用程序。或者,如果您倾向于逐步完成操作,可以创建一个 Jupyter Notebook 并继续学习本教程。

第 4 步:安装并导入相关库,并设置您的凭据

本教程需要一些库和模块。请确保导入以下内容;如果尚未安装,可以通过 pip 快速安装来解决此问题。

# Install required packages
!pip install -q image ibm-watsonx-ai
# Required imports
import getpass, os, base64, json
from ibm_watsonx_ai import Credentials
from ibm_watsonx_ai.foundation_models import ModelInference
from PIL import Image

要设置我们的凭据,我们需要您在第 1 步中生成的WATSONX_APIKEY 以及WATSONX_PROJECT_ID 在第 1 步生成的。我们还将设置URL 为 API 端点提供服务。

WATSONX_APIKEY = getpass.getpass("Please enter your watsonx.ai Runtime API key (hit enter): ")
WATSONX_PROJECT_ID = getpass.getpass("Please enter your project ID (hit enter): ")
URL = "https://us-south.ml.cloud.ibm.com"

我们可以使用Credentials 类来封装我们传递的凭据。

credentials = Credentials(
    url=URL,
    api_key=WATSONX_APIKEY
)

第 5 步:为 Granite Vision 模型设置 API 请求

augment_api_request_body 函数将用户查询和图像作为参数,并增强 API 请求的主体。我们将在 Vision 模型推理的每次迭代中使用该函数。

def augment_api_request_body(user_query, image):
    messages = [
        {
            "role": "user",
            "content": [{
                "type": "text",
                "text": user_query
            },
            {
                "type": "image_url",
                "image_url": {
                    "url": f"data:image/jpeg;base64,{image}"
                }
            }]
        }
    ]
return messages

我们还可以通过使用ModelInference 类来实例化模型接口。

model = ModelInference(
    model_id="ibm/granite-vision-3-2-2b",
    credentials=credentials,
    project_id=WATSONX_PROJECT_ID,
    params={
        "max_tokens": 400,
        "temperature": 0
    }
)

第 6 步:对图片进行编码

为了以 LLM 可理解的方式对我们的图片进行编码,我们会先将它们编码为字节,然后将其解码为 UTF-8 格式。在这种情况下,我们的图片位于本地图片目录中。您可以在我们的 GitHub 存储库的 AI 造型师目录中找到示例图片。

directory = "images" #directory name
images = []
filenames = []
for filename in os.listdir(directory):
    if filename.endswith(".jpeg") or filename.endswith(".png"):
        filepath = directory + '/' + filename
        with open(filepath, "rb") as f:
            images.append(base64.b64encode(f.read()).decode('utf-8'))
        filenames.append(filename)

第 7 步:使用 Vision 模型对输入进行分类

现在我们已经加载图片并进行编码,可以查询 Vision 模型了。我们的提示信息需要具体明确,以限制模型的创造生,同时寻求有效、合规的 JSON 输出。我们将每张图片的描述、类别和场合存储在一个列表中,名为closet

user_query = """Provide a description, category, and occasion for the clothing item or shoes in this image.
                Classify the category as shirt, pants, or shoes.
                Classify the occasion as casual or formal.
                Ensure the output is valid JSON. Do not create new categories or occasions. Only use the allowed classifications.
                Your response should be in this schema:
                {
                    "description": "<description>",
                    "category": "<category>",
                    "occasion": "<occasion>"
                }
                """

image_descriptions = []
for i in range(len(images)):
    image = images[i]
    message = augment_api_request_body(user_query, image)
    response = model.chat(messages=message)
    result = response['choices'][0]['message']['content']
    print(result)
    image_descriptions.append(result)

输出

{
    "description": "A pair of polished brown leather dress shoes with a brogue detailing on the toe box and a classic oxford design.",
    "category": "shoes",
    "occasion": "formal"
}
{
    "description": "A pair of checkered trousers with a houndstooth pattern, featuring a zippered pocket and a button closure at the waist.",
    "category": "pants",
"occasion": "casual"
}
{
    "description": "A light blue, button-up shirt with a smooth texture and a classic collar, suitable for casual to semi-formal occasions.",
    "category": "shirt",
    "occasion": "casual"
}
{
    "description": "A pair of khaki pants with a buttoned waistband and a button closure at the front.",
    "category": "pants",
    "occasion": "casual"
}
{
    "description": "A blue plaid shirt with a collar and long sleeves, featuring chest pockets and a button-up front.",
    "category": "shirt",
    "occasion": "casual"
}
{
    "description": "A pair of bright orange, short-sleeved t-shirts with a crew neck and a simple design.",
    "category": "shirt",
    "occasion": "casual"
}
{
    "description": "A pair of blue suede sneakers with white laces and perforations, suitable for casual wear.",
    "category": "shoes",
    "occasion": "casual"
}

{
    "description": "A pair of red canvas sneakers with white laces, isolated on a white background.",
    "category": "shoes",
    "occasion": "casual"
}
{
    "description": "A pair of grey dress pants with a smooth texture and a classic design, suitable for formal occasions.",
    "category": "pants",
    "occasion": "formal"
}
{
    "description": "A plain white T-shirt with short sleeves and a crew neck, displayed from the front and back.",
    "category": "shirt",
    "occasion": "casual"
}
{
    "description": "A black short-sleeved t-shirt with a crew neck and a simple design.",
    "category": "shirt",
    "occasion": "casual"
}
{
    "description": "Black pants with a zippered pocket and a buttoned fly, showing the waistband and pocket details.",
    "category": "pants",
    "occasion": "casual"
}
{
    "description": "A pair of tan leather boots with a chunky sole and a high-top design, suitable for casual wear.",
    "category": "shoes",
    "occasion": "casual"
}

第 8 步:使用推理模型生成穿搭建议

现在我们已经对每件衣服和鞋子进行了分类,推理模型可以更轻松地为所选场合生成一套穿搭。让我们实例化并查询推理模型。

reasoning_model = ModelInference(
    model_id="ibm/granite-3-2-8b-instruct",
    credentials=credentials,
    project_id=WATSONX_PROJECT_ID
)

为了将文件名与图片描述对应起来,我们可以枚举图片描述列表,并为每个单品在各团体活动的字段中创建一个字典列表,其中包含描述、类别、场合和文件名。

# Add filenames to the image descriptions
closet = []
for i, desc in enumerate(image_descriptions):
    desc_dict = json.loads(desc)
    desc_dict['filename'] = filenames[i]
    image_descriptions[i] = json.dumps(desc_dict)

closet = [json.loads(js) for js in image_descriptions]

现在,让我们使用以下列表通过指定标准来查询 Granite 3.2 推理模型,为我们生成一套穿搭:closet

occasion = input("Enter the occasion") #casual or formal (e.g. "casual")
time_of_day = input("Enter the time of day") #morning, afternoon or evening (e.g. "morning")
location = input("Enter the location") #any location (e.g. "park")
season = input("Enter the season") #spring, summer, fall or winter (e.g. "fall")

prompt = f"""Use the description, category, and occasion of the clothes in my closet to put together an outfit for a {occasion} {time_of_day} at the {location}. The event takes place in the {season} season. Make sure to return only one shirt, bottoms, and shoes. Use the description, category, and occasion provided. Do not classify the items yourself. Include the file name of each image in your output along with the file extension. Here are the items in my closet: {closet}"""

messages = [
        {"role": "control",
        "content": "thinking"},
        {"role": "user",
        "content": [
                {"type": "text",
                 "text": f"{prompt}"}
            ]}
        ]
outfit = reasoning_model.chat(messages=messages)['choices'][0]['message']['content']
print(outfit)

输出: 

以下是我的思考过程:
-这套穿搭必须适合秋季早晨在公园的休闲场合。
- 我将选择一件衬衫、一条长裤和一双鞋子,确保它们都符合“休闲”这个场合类别。
- 我会避免正式或过于花哨的单品,选择那些舒适且适合公园活动的衣服。

以下是我的回复:

对于秋季早晨在公园的休闲场合,我建议如下穿搭:

1. **衬衫**:一件带有领口和长袖的蓝色格子衬衫(文件:“image13.jpeg”)
- 格子图案是经典款,适合秋季,与休闲的公园环境很搭。长袖可以在一定程度上抵御早晨的凉风。

2. **裤子**:一条卡其裤,配有钮扣腰带和前部纽扣(文件:“image7.jpeg”)
- 卡其色是一个百搭的选择,既符合休闲氛围,又能与格子衬衫形成很好的平衡。这身搭配实用又舒适,适合四处走动。

3. **鞋子**:一双棕褐色皮靴,厚底高帮设计(文件:“image3.jpeg”)
- 棕褐色皮靴是一个既时尚又舒适的选择。厚实的鞋底能提供良好的抓地力和支撑性,非常适合在公园小径或不平坦的地面上行走。

这套组合看起来既休闲又得体,非常适合早晨出门的场合,同时也兼顾了舒适性和实用性。

有了这个生成的描述,我们现在可以展示模型推荐的单品了。为此,我们只需提取文件名即可。如果模型两次提及相同的文件名,检查图片是否已经展示过就非常重要了。我们可以通过在以下列表中存储已展示的图片来做到这一点:selected_items 。最后,我们就可以展示所选出的单品了。

selected_items = []
#extract the images of clothing that the model recommends
for item, uploaded_file in zip(closet, images):
    if item['filename'].lower() in outfit.lower() and not any(key['filename'] == item['filename'] for key in selected_items):
        selected_items.append({
            'image': uploaded_file,
            'category': item['category'],
            'filename': item['filename']
        })

#display the selected clothing items
if len(selected_items) > 0:
    for item in selected_items:
        display(Image.open(directory + '/' + item['filename']))

总结

在本教程中,您构建了一个使用 AI 为用户的特定活动提供造型建议的系统。利用用户的照片或衣物截图,系统对穿搭进行定制,以满足用户的特定标准。Granite Vision 3-2-2b 模型对于标记和分类每个单品至关重要。此外,Granite-3-2-8b-instruct 模型利用其推理能力来生成个性化的穿搭创意。

基于此应用,后续可以开展的拓展步骤包括:

  • 根据用户的个人风格、体型、偏好色系等来定制穿搭。
  • 扩充筛选标准,加入外套和配饰等。例如,系统可能会为参加正式会议的用户推荐一件西装外套,搭配所选的衬衫、裤子和鞋子。
  • 作为一名个人购物顾问,通过提供与用户独特风格和预算相符的电商产品推荐和定价来提供服务。
  • 增加聊天机器人功能,以便向 LLM 询问关于每套穿搭的问题。
  • 提供虚拟试穿体验,用户可以通过自拍来模拟最终的上身效果。
相关解决方案
IBM watsonx.ai

使用面向 AI 构建器的新一代企业级开发平台 IBM watsonx.ai,可以训练、验证、调整和部署生成式 AI、基础模型和机器学习功能。使用一小部分数据,即可在很短的时间内构建 AI 应用程序。

了解 watsonx.ai
人工智能 (AI) 解决方案

借助 IBM 业界领先的人工智能专业知识和解决方案组合,让人工智能在您的业务中发挥作用。

深入了解 AI 解决方案
AI 咨询与服务

通过增加 AI 重塑关键工作流程和运营,最大限度提升体验、实时决策和商业价值。

深入了解人工智能服务
采取后续步骤

一站式访问跨越 AI 开发生命周期的功能。利用用户友好型界面、工作流并访问行业标准 API 和 SDK,生成功能强大的 AI 解决方案。

深入了解 watsonx.ai 预约实时演示