将图片用神经网络提取的特征和csv文件中的特征进行融合,主要就是要保证读取的图片名字和csv中的名字一致,这样才能保证一致性。随机找了几张图片,举一个例子。
图片的路径为
csv中的特征为
我用vgg16提取特征,然后再与csv中的其他特征进行融合
import torch
import torchvision.models as models
from torch.utils.data import Dataset, DataLoader
import pandas as pd
from torchvision import transforms
from PIL import Image
# 数据集类
class CustomDataset(Dataset):
def __init__(self, image_folder, csv_file, transform=None):
self.csv_data = pd.read_csv(csv_file, encoding='gbk')
self.image_folder = image_folder
self.transform = transform
# 获取CSV特征的维度(除文件名列之外的特征数量)
self.num_csv_features = len(self.csv_data.columns) - 1 # 减去文件名列
def __len__(self):
return len(self.csv_data)
def __getitem__(self, idx):
img_name = self.csv_data.iloc[idx, 0] # 图片文件名列在CSV的第一列
img_path = f"{self.image_folder}/{img_name}" # 图片路径
image = Image.open(img_path).convert('RGB')
if self.transform:
image = self.transform(image)
# 返回图像和 CSV 中的其他特征
return image, torch.tensor(self.csv_data.iloc[idx, 1:], dtype=torch.float32)
# 加载预训练的VGG16模型
vgg16 = models.vgg16(pretrained=True)
vgg16_conv = vgg16.features
# 冻结卷积层的参数
for param in vgg16_conv.parameters():
param.requires_grad = False
# 自定义全连接层
class CustomNet(torch.nn.Module):
def __init__(self, input_size, num_csv_features):
super(CustomNet, self).__init__()
self.vgg = vgg16_conv
self.fc = torch.nn.Linear(input_size + num_csv_features, 128) # 假设128是中间层的大小
self.fc2 = torch.nn.Linear(128, 2) # 输出大小为2,代表两个类别
def forward(self, x, csv_features):
x = self.vgg(x)
x = x.view(x.size(0), -1)
# 拼接图像特征和CSV特征
x = torch.cat((x, csv_features), dim=1)
x = self.fc(x)
x = torch.relu(x) # 可以添加激活函数如 ReLU
x = self.fc2(x)
x = torch.sigmoid(x) # 使用 Sigmoid 将输出值映射到0到1之间
return x
# 数据预处理和加载
transform = transforms.Compose([
transforms.Resize(256),
transforms.CenterCrop(224),
transforms.ToTensor(),
transforms.Normalize(mean=[0.485, 0.456, 0.406], std=[0.229, 0.224, 0.225])
])
image_folder = r'D:\edge_download\图像\良性\T2\赵六'
csv_file = r"D:\edge_download\图像\良性\T2\file.csv"
# 创建数据集实例并获取CSV特征的维度
dataset = CustomDataset(image_folder=image_folder, csv_file=csv_file, transform=transform)
num_csv_features = dataset.num_csv_features
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)
# 训练模型
model = CustomNet(input_size=25088, num_csv_features=num_csv_features)
device = torch.device('cuda' if torch.cuda.is_available() else 'cpu') # 定义设备
model.to(device) # 将模型移动到设备
optimizer = torch.optim.Adam(model.parameters(), lr=0.001) # 定义优化器
criterion = torch.nn.BCELoss() # 定义损失函数为二元交叉熵损失
num_epochs = 10 # 定义迭代次数
for epoch in range(num_epochs):
for images, csv_features in dataloader:
images, csv_features = images.to(device), csv_features.to(device) # 将数据移动到设备
optimizer.zero_grad()
outputs = model(images, csv_features)
# 创建目标张量
target = torch.zeros_like(outputs)
target[:, 0] = 1 # 假设第一类别是正例,根据实际情况调整
loss = criterion(outputs, target)
loss.backward()
optimizer.step()
print(f'Epoch [{epoch + 1}/{num_epochs}], Loss: {loss.item()}')
这样就可以了,代码中做的是一个二分类,所以全连接之后用线性层输出为2,使用的损失函数为
torch.nn.BCELoss() ,最后开始训练模型。