基于OpenCV与Scikit的食物分类:内存不足与模型偏置问题求助
嘿,针对你开发101类食物分类器遇到的内存不足和单类别偏置问题,结合你用cv2+Scikit的技术栈,给你整理几个实用的解决方案:
一、搞定全数据集内存不足的问题
一次性加载10万+张图片的原始像素特征,内存扛不住太正常了,试试这几个思路:
- 分批加载数据:别把所有图片一股脑读进内存,写个生成器函数分批读取处理。每次只加载一批(比如32/64张)图片转成特征向量,喂给模型训练后就释放内存,这样内存占用能控制在合理范围。
- 降维优化特征:你现在用的是128×128×3的原始像素向量,维度高达49152,既占内存又容易过拟合。可以用预训练的轻量CNN(比如MobileNet)提取高层特征,把维度降到几百维,内存压力会小很多,分类效果也能提升。用OpenCV的dnn模块就能轻松实现特征提取。
- 数据类型压缩:把图片的uint8像素值转成float32并归一化(除以255),能减少一半内存占用;如果你的模型支持,甚至可以用float16进一步压缩。
二、解决单类别偏置问题
小数据集里类别分布不均,模型自然会偏向样本多的类别,这几个方法能帮你平衡:
- 分层抽样划分数据集:用Scikit的
train_test_split时,加上stratify=y参数,让训练集和测试集里每个类别的样本比例和原数据集完全一致,避免某类在训练集里占比过高。 - 设置类别权重:Scikit里的大部分分类器(比如SVM、随机森林、SGD分类器)都支持
class_weight='balanced'参数,它会自动给样本少的类别分配更高的权重,抵消偏置带来的影响。 - 针对性数据增强:给样本少的类别做数据增强,用OpenCV就能快速实现随机翻转、旋转、亮度调整等操作,生成更多样本平衡类别数量。比如:
def augment_image(image): # 随机水平翻转 if np.random.rand() > 0.5: image = cv2.flip(image, 1) # 随机小角度旋转 angle = np.random.randint(-15, 16) h, w = image.shape[:2] M = cv2.getRotationMatrix2D((w/2, h/2), angle, 1.0) image = cv2.warpAffine(image, M, (w, h)) return image
三、结合你的代码优化示例
给你的image_to_feature_vector函数加些优化,再配合分批加载的生成器:
import cv2 import numpy as np def image_to_feature_vector(image, size=(128, 128), augment=False): # 调整尺寸 image = cv2.resize(image, size) # 可选数据增强 if augment: image = augment_image(image) # BGR转RGB(适配多数预训练模型需求)+ 归一化+类型压缩 image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB).astype(np.float32) / 255.0 # 展平成特征向量 return image.flatten() # 分批加载数据的生成器 def load_data_batch(image_paths, labels, batch_size=32, augment=False): while True: # 每次迭代打乱数据 indices = np.random.permutation(len(image_paths)) for i in range(0, len(image_paths), batch_size): batch_indices = indices[i:i+batch_size] batch_feats, batch_labels = [], [] for idx in batch_indices: img = cv2.imread(image_paths[idx]) feat = image_to_feature_vector(img, augment=augment) batch_feats.append(feat) batch_labels.append(labels[idx]) yield np.array(batch_feats), np.array(batch_labels)
训练时用生成器分批喂数据,还能配合partial_fit实现增量训练:
from sklearn.linear_model import SGDClassifier # 假设你已经有了训练集的路径和标签列表 train_generator = load_data_batch(train_paths, train_labels, batch_size=32, augment=True) model = SGDClassifier(class_weight='balanced') # 训练10个epoch for epoch in range(10): for _ in range(len(train_paths)//32): X_batch, y_batch = next(train_generator) model.partial_fit(X_batch, y_batch, classes=np.unique(all_labels))
内容的提问来源于stack exchange,提问作者aaku
相关产品推荐
相关产品推荐

