PyTorch之—图像分类一(每个类对应一个文件夹)

一、数据集准备与训练

数据按文件夹组织,每个类对应一个文件夹。大多数其他的PyTorch教程和示例都希望你先按照训练集和验证集来组织文件夹,然后在训练集和验证集中再按照类别进行组织。但我认为这非常麻烦,必须从每个类别中选择一定数量的图像并将它们从训练集文件夹移动到验证集文件夹。由于大多数人会通过选择一组连续的文件作为验证集,因此选择可能存在很多偏差。

如下将使用随机打乱的方式:将数据集快速分为训练集和测试集的更好的方法。

import matplotlib.pyplot as plt
import numpy as np
import torch
from torch import nn
from torch import optim
from torch.utils.data import DataLoader
from torchvision import datasets, transforms, models


"""
    =========================== 模型训练与验证 ================================
"""
# 定义train/validation数据集加载器

data_dir = 'D:\\AI-img-classifier\\re\\train'

def load_split_train_test(datadir,valid_size = 0.2):
    train_trainsforms = transforms.Compose([transforms.Resize((224,224)),
                                            transforms.ToTensor(),])
    test_trainsforms = transforms.Compose([transforms.Resize((224,224)),
                                           transforms.ToTensor(),])

    train_data = datasets.ImageFolder(datadir,transform=train_trainsforms)
    # print("train_data大小:",train_data[0][0].size())       # 查看resize(确保图像都有3通道)
    test_data = datasets.ImageFolder(datadir,transform=test_trainsforms)

    num_train = len(train_data)                               # 训练集数量
    indices = list(range(num_train))                          # 训练集索引

    split = int(np.floor(valid_size * num_train))             # 获取20%数据作为验证集
    np.random.shuffle(indices)                                # 打乱数据集

    from torch.utils.data.sampler import SubsetRandomSampler
    train_idx, test_idx = indices[split:], indices[:split]    # 获取训练集,测试集
    train_sampler = SubsetRandomSampler(train_idx)            # 打乱训练集,测试集
    test_sampler  = SubsetRandomSampler(test_idx)

    #============数据加载器:加载训练集,测试集===================
    train_loader = DataLoader(train_data,sampler=train_sampler,batch_size=64)
    test_loader = DataLoader(test_data,sampler=test_sampler,batch_size=64)
    return train_loader,test_loader


train_loader,test_loader = load_split_train_test(data_dir, 0.2)
print(train_loader.dataset.classes)


device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = models.resnet50(pretrained=True)
print(model)

"""
   首先,我们必须冻结预训练过的层,因此在训练期间它们不会进行反向传播。
   然后,我们重新定义最后的全连接层,即使用我们的图像来训练的图层。
        我们还创建了标准(损失函数)并选择了一个优化器(在这种情况下为Adam)和学习率。
"""
for param in model.parameters():
    param.requires_grad = False

model.fc = nn.Sequential(nn.Linear(2048,512),
                         nn.ReLU(),
                         nn.Dropout(0.2),
                         nn.Linear(512,5),
                         nn.LogSoftmax(dim=1))
criterion = nn.NLLLoss()
optimizer = optim.Adam(model.fc.parameters(),lr=0.003)
model.to(device)


epochs = 10
steps = 0
running_loss = 0
train_losses,test_losses = [],[]


for epoch in range(epochs):
    for inputs,labels in train_loader:
        inputs,labels = inputs.to(device),labels.to(device)
        optimizer.zero_grad()
        out = model(inputs)
        loss = criterion(out,labels)
        loss.backward()
        optimizer.step()
        running_loss +=loss.item()
        steps +=1

        if (steps+1)%5 == 0:
            test_loss = 0
            accuracy = 0
            model.eval()
            with torch.no_grad():
                for inputs,labels in test_loader:
                    inputs, labels = inputs.to(device), labels.to(device)
                    out2 = model(inputs)
                    batch_loss = criterion(out2,labels)
                    test_loss +=batch_loss.item()

                    ps = torch.exp(out2)
                    top_pred,top_class = ps.topk(1,dim=1)
                    equals = top_class == labels.view(*top_class.shape)
                    accuracy += torch.mean(equals.type(torch.FloatTensor)).item()

            train_losses.append(running_loss/len(train_loader))
            test_losses.append(test_loss/len(test_loader))

            print(f"Epoch {epoch+1}/{epochs}"
                  f"Train loss: {running_loss/5:.3f}",
                  f"Test loss: {test_loss/len(test_loader):.3f} "
                  f"Test accuracy: {accuracy/len(test_loader):.3f}")
            running_loss = 0
            model.train()
torch.save(model,"./pytorch_Image_Training.pth")

plt.plot(train_losses,label = "Training loss")
plt.plot(test_losses, label='Validation loss')
plt.legend(frameon=False)
plt.show()

二、预测或推断

代码一:

import matplotlib.pyplot as plt
import numpy as np
import torch
from torch.utils.data import DataLoader
from torch.autograd import Variable
from torchvision import datasets, transforms



"""
    =========================== 模型预测与使用 ================================
"""
# 测试数据集,设置图像大小与训练一项
data_dir2 = 'D:\\AI-img-classifier\\re\\train'
test_trainsforms = transforms.Compose([transforms.Resize((224,224)),
                                       transforms.ToTensor(),])

device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
model = torch.load('./pytorch_Image_Training.pth')
model.eval()
print(model)


# 预测图像(输入具体图像:eg:"./xxx.jpg")
def predict_img(image):
    image_tensor = test_trainsforms(image).float()
    image_tensor = image_tensor.unsqueeze_(0)
    input = Variable(image_tensor).to(device)
    output = model(input)
    index = output.data.cpu().numpy().argmax()
    return index


# 获取随机图像
def get_random_images(num):
    data = datasets.ImageFolder(data_dir2,transform=test_trainsforms)
    classes = data.classes
    print("classes:",classes)

    indices = list(range(len(data)))
    np.random.shuffle(indices)
    idx = indices[:num]                 # 获取随机的预测数据

    from torch.utils.data.sampler import SubsetRandomSampler
    sampler = SubsetRandomSampler(idx) # 获取的预测数据再次打乱
    loader = DataLoader(data,sampler=sampler,batch_size=num)
    dataiter = iter(loader)

    images,labels = dataiter.next()
    return images,labels,classes

if __name__ == '__main__':
    path = 'D:\\AI-img-classifier\\re\\train'
    to_pil = transforms.ToPILImage()
    images, labels ,classes= get_random_images(10)
    fig = plt.figure(figsize=(10,10))
    for i in range(len(images)):
        image = to_pil(images[i])
        index = predict_img(image)
        sub = fig.add_subplot(1,len(images),i+1)
        res = int(labels[i]) == index
        str(sub.set_title(str(classes[index])))+":"+str(res)
        plt.axis('off')
        plt.imshow(image)
    plt.show()

代码二:

import torch
import matplotlib.pyplot as plt
import numpy as np
from torch.utils.data import DataLoader
from torch.autograd import Variable
from torchvision import datasets, transforms
import torchvision

"""
    =========================== 模型预测与使用 ================================
"""

def loadtestdata(img_path,num):
    testset = datasets.ImageFolder(img_path,
                                   transform=transforms.Compose([
                                       transforms.Resize((224, 224)),
                                       transforms.ToTensor()]))
    testloader = DataLoader(testset, batch_size=num,shuffle=True, num_workers=4)

    dataiter = iter(testloader)
    images,labels = dataiter.next()
    classes = testloader.dataset.classes
    print("classes:",classes)
    return images,labels,classes

def imshow(img):
    np_img = img.numpy()
    plt.imshow(np.transpose(np_img, (1, 2, 0)))
    plt.show()


def test(weghts_path,img_path,num):
    net = torch.load(weghts_path)
    images, labels, classes = loadtestdata(img_path,num)
    imshow(torchvision.utils.make_grid(images, nrow=5))                               # nrow是每行显示的图片数量,缺省值为8
    print('GroundTruth: ', " ".join('%5s' % classes[labels[j]] for j in range(num)))  # 打印(test集里图片的标签)

    outputs = net(Variable(images.cuda()))
    _, predicted = torch.max(outputs.data, 1)
    print('Predicted: ', " ".join('%5s' % classes[predicted[j]] for j in range(num)))

if __name__ == '__main__':
    weghts_path = './pytorch_Image_Training.pth'
    img_path = "D:\\AI-img-classifier\\re\\train"
    test(weghts_path,img_path,num=10)         #请输入测试图像数量

代码三:

import torch
from torch.autograd import Variable
from torchvision import transforms
import os
import shutil
from PIL import Image


def get_img(image_path):
    img_list = []
    for i in os.listdir(image_path):
        img_list.append(image_path+"/"+i)
    return img_list

def load_models():
    model = torch.load('./pytorch_Image_Training.pth')
    model.eval()
    return model

def predict_image(image_path):
    image = Image.open(image_path)

    transformation = transforms.Compose([
        transforms.Resize((224, 224)),
        transforms.ToTensor(),
        transforms.Normalize((0.5, 0.5, 0.5), (0.5, 0.5, 0.5))])

    image_tensor = transformation(image).float() # 预处理图像
    image_tensor = image_tensor.unsqueeze_(0)    # 额外添加一个批次维度,因为PyTorch将所有的图像当做批次

    if torch.cuda.is_available():
        image_tensor.cuda()

    model = load_models()

    input = Variable(image_tensor.cuda())   # 将输入变为变量
    output = model(input)                   # 预测图像的类
    index = output.data.cpu().numpy().argmax()
    return index

if __name__ == '__main__':
    image_path = r'E:/pytorch_project/re/test/'
    img_list = get_img(image_path)
    for i in img_list:
        index = predict_image(i)
        id2tag = {0:'bus',1: 'dinosaurs',2: 'elephants', 3:'flowers', 4:'hourse'}
        print(index)
        print(id2tag[index])
        target = 'E:/pytorch_project/re/'+id2tag[index]
        if os.path.exists(target):
            shutil.copy(i, target)
        else:
            os.mkdir(target)
        shutil.copy(i, target)

报错与解决:
报错1:

Traceback (most recent call last):
  File "E:/pytorch_project/pytorch_classifier/pytorch_Image_Training.py", line 77, in <module>
    for inputs,labels in train_loader:
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 615, in __next__
    batch = self.collate_fn([self.dataset[i] for i in indices])
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 232, in default_collate
    return [default_collate(samples) for samples in transposed]
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 232, in <listcomp>
    return [default_collate(samples) for samples in transposed]
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 209, in default_collate
    return torch.stack(batch, 0, out=out)
RuntimeError: invalid argument 0: Sizes of tensors must match except in dimension 0. Got 224 and 336 in dimension 2 at c:\a\w\1\s\tmp_conda_3.6_105809\conda\conda-bld\pytorch_1544094150554\work\aten\src\th\generic/THTensorMoreMath.cpp:1333

网上关于此类报错:说是图像的通道问题(有的图像没有三个通道),关于此类问题详情请查看
我的不是图像的问题(你可以打印出训练图像的通道等信息),在大神的帮助下,我查看了train_data中其中一个train_data[0][0].size()大小,发现图像只有宽进行l了Resize,高没有进行Resize,修改后代码如上。

报错2:

TypeError: exp(): argument 'input' (position 1) must be Tensor, not float

传参数据格式错误

报错3:

Traceback (most recent call last):
  File "E:/pytorch_project/pytorch_classifier/pytorch_Image_Inference.py", line 53, in <module>
    images, labels ,classes= get_random_images(5)
  File "E:/pytorch_project/pytorch_classifier/pytorch_Image_Inference.py", line 48, in get_random_images
    images,labels = dataiter.next()
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 615, in __next__
    batch = self.collate_fn([self.dataset[i] for i in indices])
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torch\utils\data\dataloader.py", line 615, in <listcomp>
    batch = self.collate_fn([self.dataset[i] for i in indices])
  File "C:\Anaconda3\envs\AI_PyTorch_GPU\lib\site-packages\torchvision\datasets\folder.py", line 103, in __getitem__
    sample = self.transform(sample)
TypeError: 'module' object is not callable

传入数据格式错误

  • 12
    点赞
  • 54
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 好的,我可以帮您编写一个图片分的 Python 代码。您需要使用深度学习框架,如 TensorFlow 或 PyTorch,来训练一个卷积神经网络模型。然后,您可以使用该模型对新的图片进行分。以下是一个简单的示例代码: ```python import tensorflow as tf import numpy as np import cv2 # 加载模型 model = tf.keras.models.load_model('model.h5') # 加载图片 img = cv2.imread('image.jpg') img = cv2.resize(img, (224, 224)) img = np.expand_dims(img, axis=) # 预测分 preds = model.predict(img) class_idx = np.argmax(preds[]) ``` 这个代码假设您已经训练好了一个模型,并将其保存为一个 H5 文件。您需要将图片加载到代码,并将其调整为模型所需的大小。然后,您可以使用模型的 predict() 方法来预测图片的分。最后,您可以使用 argmax() 函数来获取预测结果的别索引。 ### 回答2: 当然可以!以下是一个简单的图片分的Python代码示例: 首先,我们需要安装图像处理库PIL(Python Imaging Library),可以使用pip进行安装: ```python pip install pillow ``` 然后,导入必要的库和模块: ```python import os from PIL import Image ``` 接下来,定义一个函数来进行图片分: ```python def classify_images(input_folder, output_folder): # 遍历输入文件夹的图片文件 for file_name in os.listdir(input_folder): file_path = os.path.join(input_folder, file_name) # 判断文件是否为图片 if os.path.isfile(file_path) and file_name.lower().endswith(('.png', '.jpg', '.jpeg')): # 打开图片 image = Image.open(file_path) # 获取图片属性 width, height = image.size format = image.format # 创建分文件夹 category_folder = os.path.join(output_folder, format) os.makedirs(category_folder, exist_ok=True) # 保存图片到分文件夹 save_path = os.path.join(category_folder, file_name) image.save(save_path) # 关闭图片 image.close() print("图片分完成!") ``` 最后,调用函数并传入输入文件夹和输出文件夹的路径: ```python input_folder = "输入文件夹路径" output_folder = "输出文件夹路径" classify_images(input_folder, output_folder) ``` 在运行代码时,请确保将"输入文件夹路径"和"输出文件夹路径"替换为你实际的文件夹路径。这段代码将遍历输入文件夹的图片文件,并按照图片格式将其分保存到输出文件夹的相应子文件夹。 希望这个代码能够满足你的需求!如有其他问题,请随时提问。 ### 回答3: 当然,我很乐意帮你写一个图片分的Python代码!以下是一个基本的示例代码: ```python import os import shutil # 定义图片分函数 def classify_images(source_path, target_dir): # 遍历源目录下的所有文件 for file_name in os.listdir(source_path): # 获取文件的绝对路径 file_path = os.path.join(source_path, file_name) # 判断是否是文件 if os.path.isfile(file_path): # 判断文件的扩展名 ext = os.path.splitext(file_path)[1] if ext.lower() in ['.jpg', '.png', '.jpeg', '.gif']: # 创建目标目录 target_folder = os.path.join(target_dir, ext.lower().replace('.', '')) if not os.path.exists(target_folder): os.makedirs(target_folder) # 移动文件到目标目录 shutil.move(file_path, os.path.join(target_folder, file_name)) # 调用图片分函数 classify_images('源目录路径', '目标目录路径') ``` 上述代码首先导入了必要的模块,包括`os`和`shutil`。然后定义了一个名为`classify_images`的图片分函数。该函数接受源目录路径和目标目录路径作为参数。 在函数体内,首先遍历源目录下的所有文件。对于每一个文件,判断其是否是文件,并根据文件的扩展名判断是否为图片文件。如果是图片文件,则根据扩展名创建对应的目标目录,并将文件移动到目标目录下。移动文件使用了`shutil.move`函数。 最后,在主程序调用`classify_images`函数,传入对应的源目录路径和目标目录路径。 请注意,在上述代码需要将`'源目录路径'`和`'目标目录路径'`替换为你实际的源目录路径和目标目录路径。此外,你还可以根据具体需求进行适量的修改和扩展。希望这可以帮到你!
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SongpingWang

你的鼓励是我创作的最大动力!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值