From 07bae61a101b20f4fde60596ee3f278e98cccd9d Mon Sep 17 00:00:00 2001 From: zhangpu <1250681871@qq.com> Date: Wed, 29 Oct 2025 16:40:05 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BB=A3=E7=A0=81=E5=9B=9E=E6=BB=9A=EF=BC=9A?= =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=9C=AA=E7=9F=A5=E7=B1=BB=E5=88=AB=E8=B4=9F?= =?UTF-8?q?=E6=A0=B7=E6=9C=AC=E4=B9=8B=E5=90=8E=EF=BC=8C=E6=A8=A1=E5=9E=8B?= =?UTF-8?q?=E4=B8=8D=E6=94=B6=E6=95=9B=EF=BC=8C=E8=AE=AD=E7=BB=83=E6=95=88?= =?UTF-8?q?=E6=9E=9C=E7=89=B9=E5=88=AB=E5=B7=AE=EF=BC=8C=E7=8E=B0=E5=9C=A8?= =?UTF-8?q?=E8=BF=9B=E8=A1=8C=E5=9B=9E=E6=BB=9A=E3=80=82=E5=9B=9E=E6=BB=9A?= =?UTF-8?q?=E4=B9=8B=E5=90=8E=E6=95=88=E6=9E=9C=E9=9D=9E=E5=B8=B8=E4=B8=8D?= =?UTF-8?q?=E9=94=99=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- classifier/embedding_food_classifier_app.py | 23 ++++++++------ faiss_vector_db/build_faiss_index.py | 11 ++++--- faiss_vector_db/visualize_embeddings.py | 6 ++-- train/train_embedding.py | 33 +++++++++++---------- 4 files changed, 43 insertions(+), 30 deletions(-) diff --git a/classifier/embedding_food_classifier_app.py b/classifier/embedding_food_classifier_app.py index 4b9a460..956fad7 100644 --- a/classifier/embedding_food_classifier_app.py +++ b/classifier/embedding_food_classifier_app.py @@ -65,12 +65,14 @@ class EmbeddingFoodClassifierApp: BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # model_path = "../model/embedding_20251011_133653/best_embedding_model.pth" # model_path = os.path.join(BASE_DIR, "../model/embedding_20251011_133653/best_embedding_model.pth") - model_path = os.path.join(BASE_DIR, "../model/WholeIngredientRecognition/embedding_20251021_085915/best_embedding_model.pth") + model_path = os.path.join(BASE_DIR, "../model/ProcessedIngredientRecognition/embedding_20251029_100204/best_embedding_model.pth") + # model_path = os.path.join(BASE_DIR, "../model/WholeIngredientRecognition/embedding_20251024_091151/best_embedding_model.pth") # model_path = os.path.join(BASE_DIR, "../model/DishClassification/embedding_20251022_093635/best_embedding_model.pth") # FAISS索引目录 # index_dir = "../faiss_vector_db/faiss_index" # index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/faiss_index") + index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/ProcessedIngredientRecognition/faiss_index") index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/WholeIngredientRecognition/faiss_index") # index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/DishClassification/faiss_index") @@ -1087,12 +1089,13 @@ class EmbeddingFoodClassifierApp: """识别所有图片""" try: self.current_results.clear() - + score_list = [] for i, img_info in enumerate(self.uploaded_images): # 使用embedding相似度识别 if self.model is not None and self.faiss_index is not None: # 使用真实的embedding模型和FAISS索引 - predicted_class, confidence, similar_images = self.predict_with_embedding(img_info['image']) + predicted_class, confidence, similar_images,score = self.predict_with_embedding(img_info['image']) + score_list.append(score) else: # 模拟预测结果 predicted_class = np.random.choice(self.class_names) @@ -1122,7 +1125,7 @@ class EmbeddingFoodClassifierApp: # 更新UI(在主线程中) self.root.after(0, self.update_progress, i + 1, len(self.uploaded_images)) - + print('socre_list',score_list) # 识别完成,更新UI self.root.after(0, self.recognition_completed) @@ -1144,9 +1147,11 @@ class EmbeddingFoodClassifierApp: # 在FAISS索引中搜索最相似的k张图片 scores, indices = self.faiss_index.search(query_embedding, k) - print("最相似的图片索引:", indices) - print("最相似的图片分数:", scores) - + # print("最相似的图片索引:", indices) + # print("最相似的图片分数:", type(scores[0])) + # print("最相似的图片分数:", scores[0,0]) + # print("最相似的图片分数:", type(scores[0,0])) + # 收集相似图片的类别 similar_classes = [] similar_images = [] @@ -1179,12 +1184,12 @@ class EmbeddingFoodClassifierApp: vote_ratio = class_counts[predicted_class] / len(similar_classes) confidence = max_score * vote_ratio - return predicted_class, confidence, similar_images + return predicted_class, confidence, similar_images,round(scores[0,0],3) else: # 如果没有找到相似图片,随机选择一个类别 predicted_class = np.random.choice(self.class_names) confidence = 0.1 - return predicted_class, confidence, [] + return predicted_class, confidence, [],scores[0,0] except Exception as e: print(f"Embedding预测出错: {e}") diff --git a/faiss_vector_db/build_faiss_index.py b/faiss_vector_db/build_faiss_index.py index 7f01be5..d9dace3 100644 --- a/faiss_vector_db/build_faiss_index.py +++ b/faiss_vector_db/build_faiss_index.py @@ -480,12 +480,15 @@ def main(): """主函数""" # 配置参数 # MODEL_PATH = "../model/embedding_20251011_133653/best_embedding_model.pth" - # MODEL_PATH = "../model/WholeIngredientRecognition/embedding_20251021_085915/best_embedding_model.pth" - MODEL_PATH = "../model/DishClassification/embedding_20251022_093635/best_embedding_model.pth" + MODEL_PATH = "../model/ProcessedIngredientRecognition/embedding_20251029_100204/best_embedding_model.pth" + # MODEL_PATH = "../model/WholeIngredientRecognition/embedding_20251024_091151/best_embedding_model.pth" + # MODEL_PATH = "../model/DishClassification/embedding_20251022_093635/best_embedding_model.pth" + TRAIN_DIR = "../dataset/ProcessedIngredientRecognition/train" # TRAIN_DIR = "../dataset/WholeIngredientRecognition/train" - TRAIN_DIR = "../dataset/DishClassification/train" + # TRAIN_DIR = "../dataset/DishClassification/train" + OUTPUT_DIR = "ProcessedIngredientRecognition/faiss_index" # OUTPUT_DIR = "WholeIngredientRecognition/faiss_index" - OUTPUT_DIR = "DishClassification/faiss_index" + # OUTPUT_DIR = "DishClassification/faiss_index" BATCH_SIZE = 16 INDEX_TYPE = 'flat' # 'flat', 'ivf', 'hnsw' EMBEDDING_DIM = 512 diff --git a/faiss_vector_db/visualize_embeddings.py b/faiss_vector_db/visualize_embeddings.py index 4f0f60d..cab4355 100644 --- a/faiss_vector_db/visualize_embeddings.py +++ b/faiss_vector_db/visualize_embeddings.py @@ -162,10 +162,12 @@ def plot_2d(Z: np.ndarray, y: np.ndarray, title: str, out_path: Optional[str] = def main(): parser = argparse.ArgumentParser(description="可视化高维 embedding 并进行坍塌诊断") - parser.add_argument("--embeddings", type=str, default=os.path.join("DishClassification/faiss_index", "embeddings.json"), help="embeddings.json 路径") + # parser.add_argument("--embeddings", type=str, default=os.path.join("DishClassification/faiss_index", "embeddings.json"), help="embeddings.json 路径") # parser.add_argument("--embeddings", type=str, default=os.path.join("WholeIngredientRecognition/faiss_index", "embeddings.json"), help="embeddings.json 路径") - parser.add_argument("--labels", type=str, default=os.path.join("DishClassification/faiss_index", "labels.json"), help="labels.json 路径") + parser.add_argument("--embeddings", type=str, default=os.path.join("ProcessedIngredientRecognition/faiss_index", "embeddings.json"), help="embeddings.json 路径") + # parser.add_argument("--labels", type=str, default=os.path.join("DishClassification/faiss_index", "labels.json"), help="labels.json 路径") # parser.add_argument("--labels", type=str, default=os.path.join("WholeIngredientRecognition/faiss_index", "labels.json"), help="labels.json 路径") + parser.add_argument("--labels", type=str, default=os.path.join("ProcessedIngredientRecognition/faiss_index", "labels.json"), help="labels.json 路径") parser.add_argument("--method", type=str, default="pca", choices=["pca", "tsne", "umap"], help="降维方法") parser.add_argument("--seed", type=int, default=42) parser.add_argument("--max_points", type=int, default=None, help="抽样上限,避免t-SNE/UMAP过慢;None为全量") diff --git a/train/train_embedding.py b/train/train_embedding.py index facae97..6f70fe6 100644 --- a/train/train_embedding.py +++ b/train/train_embedding.py @@ -73,9 +73,11 @@ TASKS = { embedding_dim=512, batch_size=16, lr=1e-3, - triplet_margin=0.25, - center_loss_weight=0.1, - aug_strength="shape", + # triplet_margin=0.25, + triplet_margin=0.5, + # center_loss_weight=0.5, + center_loss_weight=20, + aug_strength="medium", ), } @@ -142,11 +144,11 @@ class TripletDataset(Dataset): 三元组数据集,用于三元组损失训练 每个样本包含:锚点(anchor)、正样本(positive)、负样本(negative) """ - + def __init__(self, dataset_path: str, transform=None, samples_per_class: int = 100): """ 初始化三元组数据集 - + Args: dataset_path: 数据集路径 transform: 数据变换 @@ -155,13 +157,13 @@ class TripletDataset(Dataset): self.dataset_path = dataset_path self.transform = transform self.samples_per_class = samples_per_class - + # 加载数据集 self.class_to_idx = {} self.idx_to_class = {} self.samples_by_class = defaultdict(list) self.all_samples = [] - + self._load_dataset() def _load_dataset(self): @@ -191,24 +193,24 @@ class TripletDataset(Dataset): logger.info(f"加载数据集完成:") for class_name, class_idx in self.class_to_idx.items(): logger.info(f" {class_name}: {len(self.samples_by_class[class_idx])} 张图片") - + def __len__(self): return len(self.all_samples) - + def __getitem__(self, idx): """ 获取三元组样本 - + Returns: tuple: (anchor, positive, negative, anchor_label) """ # 获取锚点样本 anchor_path, anchor_label = self.all_samples[idx] anchor_img = self._load_image(anchor_path) - + # 获取正样本(同类别的不同图片) # 需要从自己所在类别中先把自己给排除掉 - positive_candidates = [path for path in self.samples_by_class[anchor_label] + positive_candidates = [path for path in self.samples_by_class[anchor_label] if path != anchor_path] if positive_candidates: # 从这里可以看出来是随机选的 @@ -216,7 +218,7 @@ class TripletDataset(Dataset): else: positive_path = anchor_path # 如果只有一张图片,使用自己作为正样本 positive_img = self._load_image(positive_path) - + # 获取负样本(不同类别的图片) # 获得其它类别 negative_classes = [cls for cls in self.samples_by_class.keys() if cls != anchor_label] @@ -225,7 +227,7 @@ class TripletDataset(Dataset): # 随便选一个路径 negative_path = random.choice(self.samples_by_class[negative_class]) negative_img = self._load_image(negative_path) - + return anchor_img, positive_img, negative_img, anchor_label def _load_image(self, image_path: str): @@ -818,5 +820,6 @@ if __name__ == "__main__": parser = argparse.ArgumentParser() parser.add_argument("task", choices=list(TASKS.keys()), nargs="?", default="dish") args = parser.parse_args() + main("processed_ingredient") # main("whole_ingredient") - main("dish") \ No newline at end of file + # main("dish") \ No newline at end of file