代码回滚:增加未知类别负样本之后,模型不收敛,训练效果特别差,现在进行回滚。回滚之后效果非常不错。
This commit is contained in:
@@ -65,12 +65,14 @@ class EmbeddingFoodClassifierApp:
|
|||||||
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
BASE_DIR = os.path.dirname(os.path.abspath(__file__))
|
||||||
# model_path = "../model/embedding_20251011_133653/best_embedding_model.pth"
|
# 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/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")
|
# model_path = os.path.join(BASE_DIR, "../model/DishClassification/embedding_20251022_093635/best_embedding_model.pth")
|
||||||
|
|
||||||
# FAISS索引目录
|
# FAISS索引目录
|
||||||
# index_dir = "../faiss_vector_db/faiss_index"
|
# 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/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/WholeIngredientRecognition/faiss_index")
|
||||||
# index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/DishClassification/faiss_index")
|
# index_dir = os.path.join(BASE_DIR, "../faiss_vector_db/DishClassification/faiss_index")
|
||||||
|
|
||||||
@@ -1087,12 +1089,13 @@ class EmbeddingFoodClassifierApp:
|
|||||||
"""识别所有图片"""
|
"""识别所有图片"""
|
||||||
try:
|
try:
|
||||||
self.current_results.clear()
|
self.current_results.clear()
|
||||||
|
score_list = []
|
||||||
for i, img_info in enumerate(self.uploaded_images):
|
for i, img_info in enumerate(self.uploaded_images):
|
||||||
# 使用embedding相似度识别
|
# 使用embedding相似度识别
|
||||||
if self.model is not None and self.faiss_index is not None:
|
if self.model is not None and self.faiss_index is not None:
|
||||||
# 使用真实的embedding模型和FAISS索引
|
# 使用真实的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:
|
else:
|
||||||
# 模拟预测结果
|
# 模拟预测结果
|
||||||
predicted_class = np.random.choice(self.class_names)
|
predicted_class = np.random.choice(self.class_names)
|
||||||
@@ -1122,7 +1125,7 @@ class EmbeddingFoodClassifierApp:
|
|||||||
|
|
||||||
# 更新UI(在主线程中)
|
# 更新UI(在主线程中)
|
||||||
self.root.after(0, self.update_progress, i + 1, len(self.uploaded_images))
|
self.root.after(0, self.update_progress, i + 1, len(self.uploaded_images))
|
||||||
|
print('socre_list',score_list)
|
||||||
# 识别完成,更新UI
|
# 识别完成,更新UI
|
||||||
self.root.after(0, self.recognition_completed)
|
self.root.after(0, self.recognition_completed)
|
||||||
|
|
||||||
@@ -1144,9 +1147,11 @@ class EmbeddingFoodClassifierApp:
|
|||||||
|
|
||||||
# 在FAISS索引中搜索最相似的k张图片
|
# 在FAISS索引中搜索最相似的k张图片
|
||||||
scores, indices = self.faiss_index.search(query_embedding, k)
|
scores, indices = self.faiss_index.search(query_embedding, k)
|
||||||
print("最相似的图片索引:", indices)
|
# print("最相似的图片索引:", indices)
|
||||||
print("最相似的图片分数:", scores)
|
# print("最相似的图片分数:", type(scores[0]))
|
||||||
|
# print("最相似的图片分数:", scores[0,0])
|
||||||
|
# print("最相似的图片分数:", type(scores[0,0]))
|
||||||
|
|
||||||
# 收集相似图片的类别
|
# 收集相似图片的类别
|
||||||
similar_classes = []
|
similar_classes = []
|
||||||
similar_images = []
|
similar_images = []
|
||||||
@@ -1179,12 +1184,12 @@ class EmbeddingFoodClassifierApp:
|
|||||||
vote_ratio = class_counts[predicted_class] / len(similar_classes)
|
vote_ratio = class_counts[predicted_class] / len(similar_classes)
|
||||||
confidence = max_score * vote_ratio
|
confidence = max_score * vote_ratio
|
||||||
|
|
||||||
return predicted_class, confidence, similar_images
|
return predicted_class, confidence, similar_images,round(scores[0,0],3)
|
||||||
else:
|
else:
|
||||||
# 如果没有找到相似图片,随机选择一个类别
|
# 如果没有找到相似图片,随机选择一个类别
|
||||||
predicted_class = np.random.choice(self.class_names)
|
predicted_class = np.random.choice(self.class_names)
|
||||||
confidence = 0.1
|
confidence = 0.1
|
||||||
return predicted_class, confidence, []
|
return predicted_class, confidence, [],scores[0,0]
|
||||||
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
print(f"Embedding预测出错: {e}")
|
print(f"Embedding预测出错: {e}")
|
||||||
|
|||||||
@@ -480,12 +480,15 @@ def main():
|
|||||||
"""主函数"""
|
"""主函数"""
|
||||||
# 配置参数
|
# 配置参数
|
||||||
# MODEL_PATH = "../model/embedding_20251011_133653/best_embedding_model.pth"
|
# MODEL_PATH = "../model/embedding_20251011_133653/best_embedding_model.pth"
|
||||||
# MODEL_PATH = "../model/WholeIngredientRecognition/embedding_20251021_085915/best_embedding_model.pth"
|
MODEL_PATH = "../model/ProcessedIngredientRecognition/embedding_20251029_100204/best_embedding_model.pth"
|
||||||
MODEL_PATH = "../model/DishClassification/embedding_20251022_093635/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/WholeIngredientRecognition/train"
|
||||||
TRAIN_DIR = "../dataset/DishClassification/train"
|
# TRAIN_DIR = "../dataset/DishClassification/train"
|
||||||
|
OUTPUT_DIR = "ProcessedIngredientRecognition/faiss_index"
|
||||||
# OUTPUT_DIR = "WholeIngredientRecognition/faiss_index"
|
# OUTPUT_DIR = "WholeIngredientRecognition/faiss_index"
|
||||||
OUTPUT_DIR = "DishClassification/faiss_index"
|
# OUTPUT_DIR = "DishClassification/faiss_index"
|
||||||
BATCH_SIZE = 16
|
BATCH_SIZE = 16
|
||||||
INDEX_TYPE = 'flat' # 'flat', 'ivf', 'hnsw'
|
INDEX_TYPE = 'flat' # 'flat', 'ivf', 'hnsw'
|
||||||
EMBEDDING_DIM = 512
|
EMBEDDING_DIM = 512
|
||||||
|
|||||||
@@ -162,10 +162,12 @@ def plot_2d(Z: np.ndarray, y: np.ndarray, title: str, out_path: Optional[str] =
|
|||||||
|
|
||||||
def main():
|
def main():
|
||||||
parser = argparse.ArgumentParser(description="可视化高维 embedding 并进行坍塌诊断")
|
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("--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("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("--method", type=str, default="pca", choices=["pca", "tsne", "umap"], help="降维方法")
|
||||||
parser.add_argument("--seed", type=int, default=42)
|
parser.add_argument("--seed", type=int, default=42)
|
||||||
parser.add_argument("--max_points", type=int, default=None, help="抽样上限,避免t-SNE/UMAP过慢;None为全量")
|
parser.add_argument("--max_points", type=int, default=None, help="抽样上限,避免t-SNE/UMAP过慢;None为全量")
|
||||||
|
|||||||
+18
-15
@@ -73,9 +73,11 @@ TASKS = {
|
|||||||
embedding_dim=512,
|
embedding_dim=512,
|
||||||
batch_size=16,
|
batch_size=16,
|
||||||
lr=1e-3,
|
lr=1e-3,
|
||||||
triplet_margin=0.25,
|
# triplet_margin=0.25,
|
||||||
center_loss_weight=0.1,
|
triplet_margin=0.5,
|
||||||
aug_strength="shape",
|
# center_loss_weight=0.5,
|
||||||
|
center_loss_weight=20,
|
||||||
|
aug_strength="medium",
|
||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -142,11 +144,11 @@ class TripletDataset(Dataset):
|
|||||||
三元组数据集,用于三元组损失训练
|
三元组数据集,用于三元组损失训练
|
||||||
每个样本包含:锚点(anchor)、正样本(positive)、负样本(negative)
|
每个样本包含:锚点(anchor)、正样本(positive)、负样本(negative)
|
||||||
"""
|
"""
|
||||||
|
|
||||||
def __init__(self, dataset_path: str, transform=None, samples_per_class: int = 100):
|
def __init__(self, dataset_path: str, transform=None, samples_per_class: int = 100):
|
||||||
"""
|
"""
|
||||||
初始化三元组数据集
|
初始化三元组数据集
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
dataset_path: 数据集路径
|
dataset_path: 数据集路径
|
||||||
transform: 数据变换
|
transform: 数据变换
|
||||||
@@ -155,13 +157,13 @@ class TripletDataset(Dataset):
|
|||||||
self.dataset_path = dataset_path
|
self.dataset_path = dataset_path
|
||||||
self.transform = transform
|
self.transform = transform
|
||||||
self.samples_per_class = samples_per_class
|
self.samples_per_class = samples_per_class
|
||||||
|
|
||||||
# 加载数据集
|
# 加载数据集
|
||||||
self.class_to_idx = {}
|
self.class_to_idx = {}
|
||||||
self.idx_to_class = {}
|
self.idx_to_class = {}
|
||||||
self.samples_by_class = defaultdict(list)
|
self.samples_by_class = defaultdict(list)
|
||||||
self.all_samples = []
|
self.all_samples = []
|
||||||
|
|
||||||
self._load_dataset()
|
self._load_dataset()
|
||||||
|
|
||||||
def _load_dataset(self):
|
def _load_dataset(self):
|
||||||
@@ -191,24 +193,24 @@ class TripletDataset(Dataset):
|
|||||||
logger.info(f"加载数据集完成:")
|
logger.info(f"加载数据集完成:")
|
||||||
for class_name, class_idx in self.class_to_idx.items():
|
for class_name, class_idx in self.class_to_idx.items():
|
||||||
logger.info(f" {class_name}: {len(self.samples_by_class[class_idx])} 张图片")
|
logger.info(f" {class_name}: {len(self.samples_by_class[class_idx])} 张图片")
|
||||||
|
|
||||||
def __len__(self):
|
def __len__(self):
|
||||||
return len(self.all_samples)
|
return len(self.all_samples)
|
||||||
|
|
||||||
def __getitem__(self, idx):
|
def __getitem__(self, idx):
|
||||||
"""
|
"""
|
||||||
获取三元组样本
|
获取三元组样本
|
||||||
|
|
||||||
Returns:
|
Returns:
|
||||||
tuple: (anchor, positive, negative, anchor_label)
|
tuple: (anchor, positive, negative, anchor_label)
|
||||||
"""
|
"""
|
||||||
# 获取锚点样本
|
# 获取锚点样本
|
||||||
anchor_path, anchor_label = self.all_samples[idx]
|
anchor_path, anchor_label = self.all_samples[idx]
|
||||||
anchor_img = self._load_image(anchor_path)
|
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 path != anchor_path]
|
||||||
if positive_candidates:
|
if positive_candidates:
|
||||||
# 从这里可以看出来是随机选的
|
# 从这里可以看出来是随机选的
|
||||||
@@ -216,7 +218,7 @@ class TripletDataset(Dataset):
|
|||||||
else:
|
else:
|
||||||
positive_path = anchor_path # 如果只有一张图片,使用自己作为正样本
|
positive_path = anchor_path # 如果只有一张图片,使用自己作为正样本
|
||||||
positive_img = self._load_image(positive_path)
|
positive_img = self._load_image(positive_path)
|
||||||
|
|
||||||
# 获取负样本(不同类别的图片)
|
# 获取负样本(不同类别的图片)
|
||||||
# 获得其它类别
|
# 获得其它类别
|
||||||
negative_classes = [cls for cls in self.samples_by_class.keys() if cls != anchor_label]
|
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_path = random.choice(self.samples_by_class[negative_class])
|
||||||
negative_img = self._load_image(negative_path)
|
negative_img = self._load_image(negative_path)
|
||||||
|
|
||||||
return anchor_img, positive_img, negative_img, anchor_label
|
return anchor_img, positive_img, negative_img, anchor_label
|
||||||
|
|
||||||
def _load_image(self, image_path: str):
|
def _load_image(self, image_path: str):
|
||||||
@@ -818,5 +820,6 @@ if __name__ == "__main__":
|
|||||||
parser = argparse.ArgumentParser()
|
parser = argparse.ArgumentParser()
|
||||||
parser.add_argument("task", choices=list(TASKS.keys()), nargs="?", default="dish")
|
parser.add_argument("task", choices=list(TASKS.keys()), nargs="?", default="dish")
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
|
main("processed_ingredient")
|
||||||
# main("whole_ingredient")
|
# main("whole_ingredient")
|
||||||
main("dish")
|
# main("dish")
|
||||||
Reference in New Issue
Block a user