一、项目背景与数据选型

在大模型驱动的多模态推荐系统研发中,我们聚焦于构建融合文本、图像与用户行为的推荐框架。基于 LLM 的推荐语生成需求,我们选定 UCSD 发布的Amazon Product Data 数据集作为核心训练数据,其覆盖多品类商品的多模态信息,尤其适合探索 “文本 - 图像 - 交互行为” 的联合建模。

二、Amazon 数据集全景解析

2.1 数据集概况

  • 来源:UCSD 发布的 Amazon Reviews 与元数据合集,包含 1996 年至 2014 年的 14.28 亿条评论

  • 模态覆盖
    ✅ 评论数据(评分、文本、有用性投票)
    ✅ 产品元数据(标题、价格、品牌、类别)
    ✅ 图像资源(商品图片 URL)
    ✅ 关联关系(用户浏览 / 购买链路)

  • 核心优势:多模态信息完整度高,适合大模型推荐语生成与跨模态融合实验

2.2 数据分布与子集说明

数据类型 规模 特点描述
原始评论数据 20GB 含全部 14.28 亿条评论,含重复项(如同一产品不同版本评论合并)
用户评论数据 18GB 去重商品评论(8368 万条),按用户排序
5 - 核数据 9.9GB 所有用户 / 商品至少 5 条评论(4113 万条),适合稀疏性研究
深度去重数据 18GB 完全去重(8283 万条),适合情感分析任务

2.3 数据样例解析

评论数据(reviews.json)
{
  "reviewerID": "A2SUAM1J3GNN3B",
  "asin": "0000013714",
  "reviewerName": "J. McDonald",
  "helpful": [2, 3],
  "reviewText": "I bought this for my husband who plays the piano.  He is having a wonderful time playing these old hymns.  The music  is at times hard to read because we think the book was published for singing from more than playing from.  Great purchase though!",
  "overall": 5.0,
  "summary": "Heavenly Highway Hymns",
  "unixReviewTime": 1252800000,
  "reviewTime": "09 13, 2009"
}

reviewerID - 评论者的 ID,例如 A2SUAM1J3GNN3B
asin - 产品的 ID,例如 0000013714
reviewerName - 评论者的姓名
helpful - 该评论的有用程度评分,例如 2/3
reviewText - 评论的文本内容
overall - 对产品的评分
summary - 评论的摘要
unixReviewTime - 评论的时间(Unix 时间)
reviewTime - 评论的时间(原始格式)

元数据(metadata.json)
{
  "asin": "0000031852",
  "title": "Girls Ballet Tutu Zebra Hot Pink",
  "price": 3.17,
  "imUrl": "http://ecx.images-amazon.com/images/I/51fAmVkTbyL._SY300_.jpg",
  "related":
  {
    "also_bought": ["B00JHONN1S", "B002BZX8Z6", "B00D2K1M3O", "0000031909", "B00613WDTQ", "B00D0WDS9A", "B00D0GCI8S", "0000031895", "B003AVKOP2", "B003AVEU6G", "B003IEDM9Q", "B002R0FA24", "B00D23MC6W", "B00D2K0PA0", "B00538F5OK", "B00CEV86I6", "B002R0FABA", "B00D10CLVW", "B003AVNY6I", "B002GZGI4E", "B001T9NUFS", "B002R0F7FE", "B00E1YRI4C", "B008UBQZKU", "B00D103F8U", "B007R2RM8W"],
    "also_viewed": ["B002BZX8Z6", "B00JHONN1S", "B008F0SU0Y", "B00D23MC6W", "B00AFDOPDA", "B00E1YRI4C", "B002GZGI4E", "B003AVKOP2", "B00D9C1WBM", "B00CEV8366", "B00CEUX0D8", "B0079ME3KU", "B00CEUWY8K", "B004FOEEHC", "0000031895", "B00BC4GY9Y", "B003XRKA7A", "B00K18LKX2", "B00EM7KAG6", "B00AMQ17JA", "B00D9C32NI", "B002C3Y6WG", "B00JLL4L5Y", "B003AVNY6I", "B008UBQZKU", "B00D0WDS9A", "B00613WDTQ", "B00538F5OK", "B005C4Y4F6", "B004LHZ1NY", "B00CPHX76U", "B00CEUWUZC", "B00IJVASUE", "B00GOR07RE", "B00J2GTM0W", "B00JHNSNSM", "B003IEDM9Q", "B00CYBU84G", "B008VV8NSQ", "B00CYBULSO", "B00I2UHSZA", "B005F50FXC", "B007LCQI3S", "B00DP68AVW", "B009RXWNSI", "B003AVEU6G", "B00HSOJB9M", "B00EHAGZNA", "B0046W9T8C", "B00E79VW6Q", "B00D10CLVW", "B00B0AVO54", "B00E95LC8Q", "B00GOR92SO", "B007ZN5Y56", "B00AL2569W", "B00B608000", "B008F0SMUC", "B00BFXLZ8M"],
    "bought_together": ["B002BZX8Z6"]
  },
  "salesRank": {"Toys & Games": 211836},
  "brand": "Coxlures",
  "categories": [["Sports & Outdoors", "Other Sports", "Dance"]]
}

asin - 产品的 ID,例如 0000031852
title - 产品的名称
price - (抓取数据时的)产品价格,以美元计价
imUrl - 产品图片的网址
related - 相关产品(还购买过的产品、还浏览过的产品、一起购买的产品、浏览后购买的产品)
salesRank - 销售排名信息
brand - 品牌名称
categories - 该产品所属的类别列表

三、数据清洗与预处理实践

3.1 标准化处理流程

  1. ASIN 映射优化
  • 使用 BM3 开源映射函数将 10 位 ASIN 编码转换为从 0 开始的 itemID,提升 embedding 效率

  • 示例:asin: "0000013714" → itemid: "123"

  1. 品类子集筛选
  • 选定Baby、Sports、Clothing三大类(LLM 推荐论文常用数据集)

  • 挑战:Baby 品类元数据在 2018 版缺失,需从其他分类间接提取

  1. 图像资源收集
  • 脚本逻辑:通过 asin 匹配元数据中的 imgUrl,批量下载并按 itemid 命名

  • 代码部分:

import json
import csv
import os
import requests
from requests.exceptions import RequestException
 
SUFFIXES = [
    'first', 'second', 'third', 'fourth', 'fifth', 'sixth', 'seventh', 'eighth', 'ninth', 'tenth',
    'eleventh', 'twelfth', 'thirteenth', 'fourteenth', 'fifteenth', 'sixteenth', 'seventeenth',
    'eighteenth', 'nineteenth', 'twentieth', 'twenty_first', 'twenty_second', 'twenty_third',
    'twenty_fourth', 'twenty_fifth', 'twenty_sixth', 'twenty_seventh', 'twenty_eighth',
    'twenty_ninth', 'thirtieth', 'thirty_first', 'thirty_second', 'thirty_third', 'thirty_fourth',
    'thirty_fifth', 'thirty_sixth', 'thirty_seventh', 'thirty_eighth', 'thirty_ninth', 'fortieth',
    'forty_first', 'forty_second', 'forty_third', 'forty_fourth', 'forty_fifth', 'forty_sixth',
    'forty_seventh', 'forty_eighth', 'forty_ninth', 'fiftieth'
]
 
 
def load_json_data(json_path):
    """加载JSON数据到内存"""
    json_data = {}
    try:
        with open(json_path, 'r', encoding='utf-8') as f:
            for line_number, line in enumerate(f, 1):
                line = line.strip()
                if not line:
                    continue
                try:
                    item = json.loads(line)
                    asin = item.get('asin')
                    if asin:
                        json_data[asin] = item
                except json.JSONDecodeError:
                    print(f"JSON解析错误 行号: {line_number}")
    except FileNotFoundError:
        print(f"JSON文件不存在: {json_path}")
    return json_data
 
# 全局配置(可调整)
 
TIMEOUT = 40  # 下载超时时间(秒)
CHUNK_SIZE = 2048  # 下载流块大小
 
def process_items(csv_path, json_data, output_dir):
    """处理CSV并下载图片的完整实现"""
    os.makedirs(output_dir, exist_ok=True)
    success_log = os.path.join(output_dir, 'success.log')
    success_count = 0
    total_images = 0  # 总下载图片计数器
 
    with open(success_log, 'w', encoding='utf-8') as log_file:
        log_file.write("itemid,downloaded_images\n")  # CSV格式表头
 
        with open(csv_path, 'r', encoding='utf-8') as f:
            # 自动检测CSV格式
            first_line = f.readline().strip()
            sep = '\t' if '\t' in first_line else ','
            f.seek(0)
 
            reader = csv.DictReader(f, delimiter=sep)
 
            # 列名标准化处理
            field_map = {
                'asin': ['asin', 'ASIN', '商品编号'],
                'itemid': ['itemid', 'itemID', '商品ID', 'sku']
            }
            std_fields = {'asin': None, 'itemid': None}
            for orig_field in reader.fieldnames:
                for std, aliases in field_map.items():
                    if orig_field.lower() in [a.lower() for a in aliases]:
                        std_fields[std] = orig_field
                        break
 
            # 验证必要列存在
            missing = [k for k, v in std_fields.items() if not v]
            if missing:
                raise ValueError(f"CSV缺少必要列: {', '.join(missing)}")
 
            # 处理数据行
            for row in reader:
                # 获取标准化字段值
                raw_asin = row[std_fields['asin']].strip()
                raw_itemid = row[std_fields['itemid']].strip()
                line_num = reader.line_num
 
                # 空值校验
                if not raw_itemid:
                    print(f"行号 {line_num} | 错误: itemID为空")
                    continue
                if not raw_asin:
                    print(f"行号 {line_num} | itemID: {raw_itemid} | 错误: ASIN为空")
                    continue
 
                # 智能转换itemID
                try:
                    itemid = str(int(raw_itemid))  # 数字型ID去前导零
                except ValueError:
                    itemid = raw_itemid  # 非数字ID保持原样
 
                # ASIN格式校验
                asin = raw_asin.upper() if len(raw_asin) == 10 else raw_asin
                if len(asin) != 10:
                    print(f"itemID: {itemid} | 警告: ASIN {asin} 长度异常")
 
                # 查找商品数据
                item_data = json_data.get(asin) or json_data.get(asin.lower())
                if not item_data:
                    print(f"itemID: {itemid} | 原因: ASIN {asin} 未匹配到商品数据")
                    continue
 
                # 获取图片URL
                img_urls = []
                for key in ['imageURLHighRes', 'imageURL', 'image']:
                    if item_data.get(key):
                        img_urls.extend([url.strip() for url in item_data[key] if url.strip()])
                        if img_urls:
                            break
 
                if not img_urls:
                    print(f"itemID: {itemid} | 原因: 无有效图片URL")
                    continue
 
                # 执行下载
                downloaded = 0
                for idx, url in enumerate(img_urls[:len(SUFFIXES)]):
                    try:
                        suffix = SUFFIXES[idx] if idx < len(SUFFIXES) else f"extra_{idx + 1}"
                        filename = f"{itemid}_{suffix}.jpg"
                        filepath = os.path.join(output_dir, filename)
 
                        with requests.get(url, stream=True, timeout=TIMEOUT) as r:
                            r.raise_for_status()
                            with open(filepath, 'wb') as img_file:
                                for chunk in r.iter_content(CHUNK_SIZE):
                                    if chunk:
                                        img_file.write(chunk)
                        downloaded += 1
                    except Exception as e:
                        error_type = type(e).__name__
                        print(f"itemID: {itemid} | 图片 {idx + 1} | 错误类型: {error_type} | URL: {url[:50]}...")
 
                # 记录成功下载
                if downloaded > 0:
                    log_file.write(f"{itemid},{downloaded}\n")
                    success_count += 1
                    total_images += downloaded
                    print(f"itemID: {itemid} | 成功下载 {downloaded}张 → {output_dir}")
 
        # 输出最终统计
        print(f"\n{'统计结果':-^30}")
        print(f"▪ 成功商品数: {success_count}")
        print(f"▪ 总下载图片: {total_images}")
        print(f"▪ 详细记录: {success_log}")
        print(f"{'':-^30}")
  1. 处理结果统计
  • Sports 品类:5013 个类别,18086 张图
    在这里插入图片描述
  • Clothing 品类:4945 个类别,23264 张图片
    在这里插入图片描述

四、多模态建模挑战

  1. 数据稀疏性
  • 约 30% 商品无图片数据,需设计文本补全策略(如 LLM 生成图像描述)

  • 部分长尾品类用户交互量不足 5 次,冷启动问题突出

  1. 模态对齐难题
  • 文本评论(抽象情感)与图像(直观视觉)的语义鸿沟需跨模态编码器解决

  • 商品关联关系(also_bought)与用户行为数据的联合建模需设计图神经网络模块

五、本周进展与资源链接

5.1 已完成工作

三大品类数据清洗脚本开发(去重、ASIN 映射、图像下载)

构建标准化数据集结构:

./dataset/amazon/

├── metadata.json       # 产品元数据

├── reviews\_clothing.csv # 清洗后评论

├── images/            # 按itemid命名的图片

└── asin2itemid.json   # 映射表

5.2 数据集下载资源

六、下周计划

  1. 搭建多模态特征提取框架:
  • 文本:BERT-base 提取评论 embedding

  • 图像:CLIP-ViT 提取视觉特征

  1. 设计 LLM 推荐语生成 Prompt 模板,结合用户历史交互与商品多模态信息

  2. 探索冷启动场景下的跨模态协同过滤算法,验证图像补全方案效果

(持续更新中,欢迎交流多模态推荐技术细节!)

Logo

火山引擎开发者社区是火山引擎打造的AI技术生态平台,聚焦Agent与大模型开发,提供豆包系列模型(图像/视频/视觉)、智能分析与会话工具,并配套评测集、动手实验室及行业案例库。社区通过技术沙龙、挑战赛等活动促进开发者成长,新用户可领50万Tokens权益,助力构建智能应用。

更多推荐