)
本文介绍了基于COCO格式制作小型犬类图像数据集的完整流程。首先创建包含annotations和images的标准文件夹结构图像需按名称_索引.jpg格式命名。通过CSV文件存储图像ID、描述文本和数据集划分信息经脚本转换生成5个关键JSON文件包括训练集、验证集和测试集。配置YAML文件指定路径和训练参数后使用BLIP模型进行3个epoch的微调训练并输出评估指标。最终模型权重和预测结果保存在output目录可通过修改demo.py进行测试为每张图像生成多个描述文本。整个流程展示了从小型数据集构建到模型训练测试的标准化方法。数据集的制作为了方便训练数据集仿照COCO的格式进行的制作。我这里用了20张小狗的照片进行演示。数据集样例如下步骤1新建my_blip_dataset文件夹在里面分别建annotations和images文件夹。步骤2在images文件中新建“val2014”文件夹用于存储图像(把所有的图像放进去即可)。如下所示。注意为了方便训练这里的图像命名方式有要求格式为图像名称_索引.jpg。例如dog_1.jpg、dog_2.jpg步骤3在annotations文件夹新建coco_gt文件夹新建ann.csv文件写入描述信息。ann.csv内容如下可以用WPS或者excel编写内容。三列分别为图像id、caption、split(train为训练val为验证test为测试)image_id即把图像后缀去掉仅仅保留图像名字。我这里是给每个图生成了3个描述你也可以一个或者更多描述。步骤4运行tools/csv2json.py生成5个json文件。目录格式如下这里一定要检查是否正确不然训练会报错annotations/|-- ann.csv|-- coco_gt| |-- coco_karpathy_test_gt.json| -- coco_karpathy_val_gt.json|-- coco_karpathy_test.json|-- coco_karpathy_train.json|-- coco_karpathy_val.json其中coco_karpathy_train.json内容大体如下即格式为{captionimageimage_id}[ { caption: a brown dog in a caged area looks up at, image: val2014/dog_0.jpg, image_id: dog_0 }, { caption: a puppy standing inside of a cage looking, image: val2014/dog_0.jpg, image_id: dog_0 } ..................]coco_karpathy_val.json中的格式为{image,caption,image_id}大体内容如下coco_karpathy_test.json和coco_karpathy_val.json格式一样[ { image: val2014/dog_10.jpg, caption: [ a little brown dog laying on top of a table, a very cute little puppy laying on the floor, the dog is laying on the floor beside the computer ], image_id: dog_10 }, { image: val2014/dog_11.jpg, caption: [ two small puppies on the grass together, two small dogs sitting on the grass and one of them, two puppies laying on a grass covered field ], image_id: dog_11 }...........................]coco_gt文件下的coco_karpathy_val_gt.json格式为: { annotations: [ {image_id: 10,caption: a little brown dog laying on top of a table,id:0},{image_id:11,caption:.....,id:1} ................ ] images:[{id:10},{id:11}......] }最终的目录形式如下|-- annotations(标签文件夹根目录)| |-- ann.csv (存储标签即图像的描述信息)| |-- coco_gt (存放真实的标签文件用于后期评价指标的计算)| |-- coco_karpathy_test.json (测试集)| |-- coco_karpathy_train.json (训练集)| |-- coco_karpathy_val.json (验证集)||-- images(图像文件夹根目录)-- val2014 (存储图像)训练步骤5在configs/下新建caption_mydata.yaml内容如下image_root: my_blip_dataset/images/ ann_root: my_blip_dataset/annotations coco_gt_root: my_blip_dataset/annotations/coco_gt pretrained: weights/model_base_caption_capfilt_large.pth vit: base vit_grad_ckpt: False vit_ckpt_layer: 0 batch_size: 2 # 小批量适合测试 init_lr: 1e-5 image_size: 384 max_length: 20 min_length: 5 num_beams: 3 prompt: a picture of weight_decay: 0.05 min_lr: 0 max_epoch: 3 # 少量epochs进行测试步骤6在终端输入命令开启训练python train_caption.py --config configs/caption_mydata.yaml训练打印如下(部分)Using downloaded and verified file: my_blip_dataset/annotations/coco_gt\coco_karpathy_test_gt.jsonloading annotations into memory...Done (t0.00s)creating index...index created!Loading and preparing results...DONE (t0.00s)creating index...index created!tokenization...setting up scorers...computing Bleu score...{testlen: 28, reflen: 28, guess: [28, 25, 22, 19], correct: [16, 8, 5, 3]}ratio: 0.9999999999642857Bleu_1: 0.571Bleu_2: 0.428Bleu_3: 0.346Bleu_4: 0.285computing METEOR score...METEOR: 0.225computing Rouge score...ROUGE_L: 0.492computing CIDEr score...CIDEr: 1.399Bleu_1: 0.571Bleu_2: 0.428Bleu_3: 0.346Bleu_4: 0.285METEOR: 0.225ROUGE_L: 0.492CIDEr: 1.399Training time 0:00:58训练的权重和结果会在output下面如下output/ -- Caption_coco |-- checkpoint_best.pth |-- config.yaml |-- log.txt -- result |-- test_epoch0.json |-- test_epoch0_rank0.json |-- test_epoch1.json |-- test_epoch1_rank0.json |-- test_epoch2.json |-- test_epoch2_rank0.json |-- val_epoch0.json |-- val_epoch0_rank0.json |-- val_epoch1.json |-- val_epoch1_rank0.json |-- val_epoch2.json -- val_epoch2_rank0.json测试修改demo.py中的model_path和image_path开启测试我这里一个图生成3个描述。a puppy that is looking up at the camera while in the kennel, with its head tilted to the side a small dog in a caged area with his owner behind him, wearing a red collar and leash a dog inside of a cage looking up to its ear and body in the air关于报错如果报错如下tokenization... Traceback (most recent call last): File E:\BLIP\train_caption.py, line 208, in module main(args, config) File E:\BLIP\train_caption.py, line 148, in main coco_val coco_caption_eval(config[coco_gt_root],val_result_file,val) File E:\BLIP\data\utils.py, line 106, in coco_caption_eval coco_eval.evaluate() File D:\ProgramData\Anaconda3\envs\pytorch121\lib\site-packages\pycocoevalcap\eval.py, line 33, in evaluate gts tokenizer.tokenize(gts) File D:\ProgramData\Anaconda3\envs\pytorch121\lib\site-packages\pycocoevalcap\tokenizer\ptbtokenizer.py, line 54, in tokenize p_tokenizer subprocess.Popen(cmd, cwdpath_to_jar_dirname, \ File D:\ProgramData\Anaconda3\envs\pytorch121\lib\subprocess.py, line 858, in __init__ self._execute_child(args, executable, preexec_fn, close_fds, File D:\ProgramData\Anaconda3\envs\pytorch121\lib\subprocess.py, line 1327, in _execute_child hp, ht, pid, tid _winapi.CreateProcess(executable, args, FileNotFoundError: [WinError 2] 系统找不到指定的文件。解决方案修改ptbtokenizer.py中的class PTBTokenizer如下class PTBTokenizer: Python wrapper of Stanford PTBTokenizer def __init__(self, verboseTrue): self.verbose verbose # 确保JAR路径正确 self.jar_path os.path.join(os.path.dirname(os.path.abspath(__file__)), stanford-corenlp-3.4.1.jar) if not os.path.exists(self.jar_path): raise FileNotFoundError(f找不到JAR文件: {self.jar_path}) def tokenize(self, captions_for_image): # 检查输入是否为空 if not captions_for_image: print(警告: 输入的captions_for_image为空) return {} # 提取句子并检查 sentences_list [] image_id [] for k, v in captions_for_image.items(): for c in v: image_id.append(k) sentence c[caption].replace(\n, ).strip() sentences_list.append(sentence) if not sentences_list: print(警告: 提取的句子列表为空) return {} sentences \n.join(sentences_list) # print(f待处理的句子数量: {len(sentences_list)}) # print(f第一个句子预览: {sentences_list[0][:50]}...) # 准备临时文件 path_to_jar_dirname os.path.dirname(os.path.abspath(__file__)) try: # 使用更安全的临时文件处理 with tempfile.NamedTemporaryFile(modew, deleteFalse, dirpath_to_jar_dirname, encodingutf-8) as tmp_file: tmp_file.write(sentences) tmp_file_name tmp_file.name # 验证临时文件是否创建成功 if not os.path.exists(tmp_file_name): raise FileNotFoundError(f临时文件未创建: {tmp_file_name}) # 构建命令 - 使用绝对路径 cmd [ java, -cp, self.jar_path, edu.stanford.nlp.process.PTBTokenizer, -preserveLines, -lowerCase, os.path.basename(tmp_file_name) ] # 执行命令 - 改进的方式 # if self.verbose: # print(f执行命令: { .join(cmd)}) # print(f工作目录: {path_to_jar_dirname}) # 使用shellTrue并捕获错误输出 process subprocess.Popen( cmd, cwdpath_to_jar_dirname, stdoutsubprocess.PIPE, stderrsubprocess.PIPE, shellTrue, textTrue # 使用text模式替代universal_newlines ) # 通信并获取结果 stdout, stderr process.communicate() # 检查是否有错误 if process.returncode ! 0: print(f命令执行错误 (返回码: {process.returncode})) print(f错误输出: {stderr}) return {} # if self.verbose and stderr: # print(f命令警告输出: {stderr}) # 处理结果 lines stdout.split(\n) # 确保行数匹配 if len(lines) ! len(sentences_list): print(f警告: 处理后的行数({len(lines)})与输入句子数({len(sentences_list)})不匹配) # 创建结果字典 final_tokenized_captions_for_image {} for k, line in zip(image_id, lines[:len(image_id)]): # 防止索引溢出 if k not in final_tokenized_captions_for_image: final_tokenized_captions_for_image[k] [] # 移除标点并处理 tokenized_caption .join([w for w in line.strip().split() if w and w not in PUNCTUATIONS]) final_tokenized_captions_for_image[k].append(tokenized_caption) return final_tokenized_captions_for_image except Exception as e: print(f分词过程中发生错误: {str(e)}) return {} finally: # 确保临时文件被删除 if tmp_file_name in locals() and os.path.exists(tmp_file_name): try: os.remove(tmp_file_name) except Exception as e: print(f删除临时文件失败: {str(e)})评价指标说明训练所用的评价指标为Bleu、Meteor、Rouge_L、CIDEr、SPICEBleu指生成的句子和参考(真实)句子在n-gram(连续n个词)上的重合程度。统计从 1-gram 到 4-gram 的精确率然后加权几何平均。BLEU-1、BLEU-4 分别指只算1-gram或主要算4-gram。特点偏重精确率生成的内容是否都在参考中出现。对词序不敏感“猫追狗”和“狗追猫”的BLEU可能很高。适合评估机器翻译但在图文描述中过于机械不擅长评价同义词或语义相似性。METEOR核心思想结合精确率和召回率生成的内容覆盖了多少参考信息并引入同义词匹配和词干还原。计算方式先进行词对齐包括同义词和词干形式计算加权 F 值再减去词序错乱的惩罚项。特点与人类判断的相关性比 BLEU 更高。能处理同义词例如 “boy” ↔ “kid”。对词序敏感“dog bites man” 和 “man bites dog” 分数很低。在图文描述中表现稳健但需要语言的词干库和同义词库。示例分析会将 “playing soccer” 与 “kicks a soccer ball” 进行语义匹配play ↔ kick 在运动语境下可部分匹配分数会比 BLEU 高。ROUGE_L核心思想专注于召回率衡量生成文本和参考文本之间的最长公共子序列。计算方式找到生成句和参考句的最长公共子序列不一定要连续但要保持顺序然后计算基于该序列的 F 值通常报告 F 值。特点评价流畅度和信息覆盖程度因为最长公共子序列能反映词序和句法结构。更适合文本摘要任务在图文描述中用于核验关键信息是否被覆盖。缺点短句或重复词可能获得虚高分数。示例分析最长公共子序列 “a boy soccer on the field” (去掉 “playing” / “is” 等)能捕捉到主语和地点但动词细节丢失。CIDEr (Consensus-based Image Description Evaluation)核心思想专门为图文描述设计的指标通过TF-IDF 加权 n-gram衡量生成内容与多数参考描述的一致性。计算方式对每个 n-gram 计算其在生成句中的频率TF与在所有参考语料库中的稀有度IDF的乘积然后与参考句的向量计算余弦相似度。特点善于惩罚通用废话例如 “there is a” 会被 IDF 降低权重奖励独特且正确的细节如 “soccer” 比 “thing” 分高。图文描述任务中的首选指标之一与人类判断高度相关。需要多句参考描述才能稳定。SPICE (Semantic Propositional Image Caption Evaluation)核心思想从语义场景图的角度评估将描述转换为主体, 关系, 客体三元组再比较F 值。计算方式用语义解析器将句子转换成图结构包含对象、属性、关系然后与参考图的对应项匹配。特点能评价语义完整性而非词面重叠。例如“男孩踢球” vs “孩子在玩球” – 虽有词不同但语义结构相似。对词序、单词形式不敏感但对关系的正确性很敏感。计算较慢需要语义解析器不支持中文。常常作为 CIDEr 的补充使用CIDEr 偏词汇细节SPICE 偏高层语义。示例分析生成图(boy) – playing → (soccer) 参考图(young boy) – kicking → (soccer ball)。SPICE 会匹配主体boy ≈ young boy和客体 soccer ≈ soccer ball但关系playing vs kicking略有差异整体得分中等偏高。指标核心依据擅长度局限性BLEUn-gram 精确率 短句惩罚机械的词汇重合度忽略召回率和同义词METEOR带同义词/词干对齐的 F 值语义灵活匹配、词序惩罚依赖外部语言资源ROUGE_L最长公共子序列的 F 值信息覆盖和结构流畅度对重复词敏感原为摘要设计CIDErTF-IDF 加权的 n-gram 余弦相似度独特细节、与多数参考一致需要多参考句偏爱短语匹配SPICE场景图对象、属性、关系F 值高层语义正确性计算慢不支持中文BLIP模型主要依赖CIDEr评价指标因为它最适合图文描述同时观测SPICE确保语义不偏论文报告通常会列出BLEU-4, METEOR, ROUGE_L, CIDEr, SPICE五件套方便与其他模型全面对比。选模型做推理如果你的应用更看重事实准确性如医疗、教育重点看SPICE更看重描述丰富性如社交媒体的自动配文重点看CIDEr。简单记忆口诀BLEU看词对METEOR懂同义ROUGE_L保流畅CIDEr抓重点SPICE挖语义。