【问题记录】pytorch自定义数据集 No such file or directory, invalid index of a 0-dim

  • Post author:
  • Post category:其他


保存模型:



保存整个神经网络的结构和模型参数

torch.save(mymodel, ‘mymodel.pkl’)

只保存神经网络的模型参数

torch.save(mymodel.state_dict(), ‘mymodel_params.pkl’)

导入模型:

mymodel = torch.load(‘mymodel.pkl’)

x=x.view(1,1,4,5) 意思是将 x 矩阵转换成 (1,1,4,5) 的四维矩阵,第一个 1是样本数,第二个1是通道数,第三个 4 和第四个 5 是高度和宽度。



卷积层

卷积层是用一个固定大小的矩形区去席卷原始数据,将原始数据分成一个个和卷积核大小相同的小块,然后将这些小块和卷积核相乘输出一个卷积值(注意:这里是一个单独的值,不再是矩阵了)。

conv2d 是二维度卷积,对数据在宽度和高度两个维度上进行卷积。

函数:

torch.nn.functional.conv2d(input, weight, bias=None, stride=1, padding=0, dilation=1, groups)

weight:卷积核权重,也就是卷积核本身,是一个四维度数组,(out_channels, in_channels/groups, kH, kW

Out_channels)。

out_channels是卷积核输出层的神经元个数,也就是这层有多少个卷积核,;in_channels 输入通道数,kH kW是卷积核的高度和宽

第一个代码:

train_hd=pandas.read_csv('C:\\Users\\number.csv')
train_path='C:\\Users\\pic'


class Mydataset(Dataset):
    def __init__(self,df_data,data_dir='./',transform=None):
        super().__init__()
        self.df=df_data.values
        self.data_dir=data_dir
        self.transform=transform
    def __len__(self):
        return len(self.df)
    def __getiem__(self,idex):
        c,img_name,label=self.df[idex]
        img_path=os.path.join(self.data_dir,img_name)
        image=cv2.imread(img_path)
        if self.transform is not None:
            image=self.transform(image)
        return image,label


transforms_train=transforms.Compose([
    transforms.ToPILImage(),
    transforms.RandomHorizontalFlip(),
    transforms.RandomRotation(10),
    transforms.ToTensor(),
    transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))])

train_data=Mydataset(train_hd,train_path,transform=transforms_train)
BATCH_SIZE=64
train_loader=DataLoader(train_data,batch_size=BATCH_SIZE,shuffle=True)
print(train_data.__len__())
print(train_data.__getiem__(100))
# --------------------------------------------------------


hidden_layer = 3
input_data = 3
output_data = 2
x = Variable(torch.randn(BATCH_SIZE, input_data), requires_grad= False)
y = Variable(torch.randn(BATCH_SIZE, output_data), requires_grad =False)
w1 = Variable(torch.randn(input_data, hidden_layer) , requires_grad= True)
w2 = Variable(torch.randn(hidden_layer, output_data) , requires_grad =True)
epochn = 100  # grad.data. zero() 全部置零,
learning_rate = 1e-6
for epoch in range(epochn):
 y_pred = x.mm(w1).clamp(min=0).mm(w2)
 loss = (y_pred - y).pow(2).sum()
 print("Epoch:{},Loss:{:.4f}".format(epoch,loss.item()))
 loss.backward()
 w1.data -= learning_rate * w1.grad.data
 w2.data -= learning_rate * w2.grad.data
 w1.grad.data.zero_()
 w2.grad.data.zero_()

之后的代码:

import torch.nn.functional as F

import torch
import torch.nn as nn
from torch.autograd import Variable

from torchvision import transforms
from torch.utils.data.dataset import Dataset
from torch.utils.data.dataloader import DataLoader
from PIL import Image

import torch.optim as optim
import os

# ***************************初始化一些函数********************************
# torch.cuda.set_device(gpu_id)#使用GPU
learning_rate = 0.0001  # 学习率的设置

# *************************************数据集的设置****************************************************************************
root = os.getcwd() + '/data/'  # 数据集的地址


# 定义读取文件的格式
def default_loader(path):
    return Image.open(path).convert('RGB')


class MyDataset(Dataset):
    # 创建自己的类: MyDataset,这个类是继承的torch.utils.data.Dataset
    # **********************************  #使用__init__()初始化一些需要传入的参数及数据集的调用**********************
    def __init__(self, txt, transform=None, target_transform=None):
        super(MyDataset, self).__init__()
        # 对继承自父类的属性进行初始化
        imgs = []
        fh = open("./data/num.txt", 'r')
        # 按照传入的路径和txt文本参数,以只读的方式打开这个文本
        for line in fh:  # 迭代该列表#按行循环txt文本中的内
            line = line.strip('\n')
            line = line.rstrip('\n')
            # 删除 本行string 字符串末尾的指定字符,这个方法的详细介绍自己查询python
            words = line.split()

            # 用split将该行分割成列表  split的默认参数是空格,所以不传递任何参数时分割空格
            imgs.append((words[0], int(words[1])))
            # 把txt里的内容读入imgs列表保存,具体是words几要看txt内容而定
        # 很显然,根据我刚才截图所示txt的内容,words[0]是图片信息,words[1]是lable
        self.imgs = imgs
        self.transform = transform
        self.target_transform = target_transform

        # *************************** #使用__getitem__()对数据进行预处理并返回想要的信息**********************

    def __getitem__(self, index):  # 这个方法是必须要有的,用于按照索引读取每个元素的具体内容
        fn, label = self.imgs[index]
        print(fn+'mm')
        # fn是图片path #fn和label分别获得imgs[index]也即是刚才每行中word[0]和word[1]的信息
        img_path = os.path.join("C:/Users/pic/", fn)
        img = Image.open(img_path).convert('RGB')
        # 按照路径读取图片
        if self.transform is not None:
            img = self.transform(img)
        # 数据标签转换为Tensor
        return img, label

    # return回哪些内容,那么我们在训练时循环读取每个batch时,就能获得哪些内容
    # **********************************  #使用__len__()初始化一些需要传入的参数及数据集的调用**********************

    def __len__(self):
        # 这个函数也必须要写,它返回的是数据集的长度,也就是多少张图片,要和loader的长度作区分
        return len(self.imgs)


class Net(nn.Module):  # 定义网络,继承torch.nn.Module
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(1, 6, 5)  # 卷积层
        self.pool = nn.MaxPool2d(2, 2)  # 池化层
        self.conv2 = nn.Conv2d(6, 16, 5)  # 卷积层
        self.fc1 = nn.Linear(16 * 5 * 5, 120)  # 全连接层
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 2)  # 2个输出

    def forward(self, x):  # 前向传播

        x = self.pool(F.relu(self.conv1(x)))  # F就是torch.nn.functional
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)  # .view( )是一个tensor的方法,使得tensor改变size但是元素的总数是不变的。
        # 从卷基层到全连接层的维度转换

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return


net = Net()  # 初始化一个卷积神经网络leNet-
train_data = MyDataset(txt=root + 'num.txt', transform=transforms.Compose([
    transforms.Resize((32, 32)),
    # 将图片缩放到指定大小(h,w)或者保持长宽比并缩放最短的边到int大小

    transforms.CenterCrop(32),
    transforms.ToTensor()])
                       )

train_loader = DataLoader(dataset=train_data, batch_size=2, shuffle=True)
# batch_size:从样本中取多少张,每一次epoch都会输入batch_size张
print('num_of_trainData:', len(train_data))


def trainandsave():
    # 神经网络结构
    print('h')
    net = Net()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # 学习率为0.001
    criterion = nn.CrossEntropyLoss()  # 损失函数也可以自己定义,我们这里用的交叉熵损失函数
    # 训练部分
    i = 0
    for epoch in range(5):  # 训练的数据量为5个epoch,每个epoch为一个循环
        # 每个epoch要训练所有的图片,每训练完成200张便打印一下训练的效果(loss值)
        running_loss = 0.0  # 定义一个变量方便我们对loss进行输出

        for i, data in enumerate(train_loader, 0):  # 这里我们遇到了第一步中出现的trailoader,代码传入数据
            # enumerate是python的内置函数,既获得索引也获得数据
            # get the inputs

            inputs, labels = data  # data是从enumerate返回的data,包含数据和标签信息,分别赋值给inputs和labels

            # wrap them in Variable
            inputs, labels = Variable(inputs), Variable(labels)  # # 转换数据格式用Variable

            optimizer.zero_grad()  # 梯度置零,因为反向传播过程中梯度会累加上一次循环的梯度

            # forward + backward + optimize
            outputs = net(inputs)  # 把数据输进CNN网络net
            loss = criterion(outputs, labels)  # 计算损失值
            loss.backward()  # loss反向传播
            optimizer.step()  # 反向传播后参数更新
            running_loss += loss.data[0]  # loss累加
            if i % 20 == 19:
                print('[%d, %5d] loss: %.3f' %
                      (epoch + 1, i + 1, running_loss / 20))  # 然后再除以200,就得到这两百次的平均损失值
                running_loss = 0.0  # 这一个200次结束后,就把running_loss归零,下一个200次继续使用

    print('Finished Training')
    # 保存神经网络
    torch.save(net, 'net.pkl')
    # 保存整个神经网络的结构和模型参数
    torch.save(net.state_dict(), 'net_params.pkl')


if __name__ == '__main__':

    for i, data in enumerate(train_loader, 0):


        print(i)

报错信息:

在这里插入图片描述

在这里插入图片描述

发现每次batch_size修改后对迭代有影响。只有batch_size为1时才进入了main 的循环,很奇怪。然后 fp = builtins.open(filename, “rb”)

FileNotFoundError: [Errno 2] No such file or directory: ‘C:/Users/pic/a_236.jpg’

一直以为自己文件夹下面有图片,但是仔细检查才知道自己那部分图片是png后缀结尾的,天哪,捣鼓了一下午居然就因为这个原因,我狂汗阿。。。。真的太不仔细了。。。。粗心害死人。。。。。

但是我也产生了疑问,难道pytorch的训练图片只能说jpg格式吗?在书上也没看到过这一点。

另一个报错:

TypeError: pic should be Tensor or ndarray. Got <class ‘PIL.Image.Image’>.

方法:删去transform的toPILIMAGE。

用程序将png后缀文件改成jpg之后仍然有错:

在这里插入图片描述

看来文件已经都能迭代成功了,但是参数有问题。

发现在net中的第一卷积层是这样的:

self.conv1 = nn.Conv2d(2, 6, 5) # 卷积层

这个函数第一个参数为输入的通道数,第二个参数为输出的通道数。而我图片是3通道

改为:

self.conv1 = nn.Conv2d(3, 6, 5) # 卷积层

之后的报错:

loss.data[0] # loss累加

IndexError: invalid index of a 0-dim

在这里插入图片描述

版本原因,应该把data[0]写成.item()

修改所有错误终于开始训练了:

在这里插入图片描述

上面结果的全部代码:

import cv2
import torch.nn.functional as F

import torch
import torch.nn as nn
from torch.autograd import Variable

from torchvision import transforms
from torch.utils.data.dataset import Dataset
from torch.utils.data.dataloader import DataLoader
from PIL import Image

import torch.optim as optim
import os

# ***************************初始化一些函数********************************
# torch.cuda.set_device(gpu_id)#使用GPU
learning_rate = 0.0001  # 学习率的设置

# *************************************数据集的设置****************************************************************************
root = os.getcwd() + '\\data\\'  # 数据集的地址


# 定义读取文件的格式
def default_loader(path):
    return Image.open(path).convert('RGB')


class MyDataset(Dataset):
    # 创建自己的类: MyDataset,这个类是继承的torch.utils.data.Dataset
    # **********************************  #使用__init__()初始化一些需要传入的参数及数据集的调用**********************
    def __init__(self, txt, transform=None, target_transform=None,loader=default_loader):
        super(MyDataset, self).__init__()
        # 对继承自父类的属性进行初始化
        imgs = []
        fh = open(txt, 'r')
        # 按照传入的路径和txt文本参数,以只读的方式打开这个文本
        for line in fh:  # 迭代该列表#按行循环txt文本中的内
            line = line.strip('\n')
            line = line.rstrip('\n')
            # 删除 本行string 字符串末尾的指定字符,这个方法的详细介绍自己查询python
            words = line.split()

            # 用split将该行分割成列表  split的默认参数是空格,所以不传递任何参数时分割空格
            imgs.append((words[0], int(words[1])))
            # 把txt里的内容读入imgs列表保存,具体是words几要看txt内容而定
        # 很显然,根据我刚才截图所示txt的内容,words[0]是图片信息,words[1]是lable
        self.imgs = imgs
        self.transform = transform
        self.target_transform = target_transform

        # *************************** #使用__getitem__()对数据进行预处理并返回想要的信息**********************

    def __getitem__(self, index):  # 这个方法是必须要有的,用于按照索引读取每个元素的具体内容
        fn, label = self.imgs[index]

        # fn是图片path #fn和label分别获得imgs[index]也即是刚才每行中word[0]和word[1]的信息
        img_path = os.path.join("C:\\Users\\pic\\", fn)
        img = Image.open(img_path).convert('RGB')
        # 按照路径读取图片
        if self.transform is not None:
            img = self.transform(img)
        # 数据标签转换为Tensor
        return img, label

    # return回哪些内容,那么我们在训练时循环读取每个batch时,就能获得哪些内容
    # **********************************  #使用__len__()初始化一些需要传入的参数及数据集的调用**********************

    def __len__(self):
        # 这个函数也必须要写,它返回的是数据集的长度,也就是多少张图片,要和loader的长度作区分
        return len(self.imgs)


class Net(nn.Module):  # 定义网络,继承torch.nn.Module
    def __init__(self):
        super(Net, self).__init__()
        self.conv1 = nn.Conv2d(3, 6, 5)  # 卷积层
        self.pool = nn.MaxPool2d(2, 2)  # 池化层
        self.conv2 = nn.Conv2d(6, 16, 5)  # 卷积层
        self.fc1 = nn.Linear(16 * 5 * 5, 120)  # 全连接层
        self.fc2 = nn.Linear(120, 84)
        self.fc3 = nn.Linear(84, 2)  # 2个输出

    def forward(self, x):  # 前向传播

        x = self.pool(F.relu(self.conv1(x)))  # F就是torch.nn.functional
        x = self.pool(F.relu(self.conv2(x)))
        x = x.view(-1, 16 * 5 * 5)  # .view( )是一个tensor的方法,使得tensor改变size但是元素的总数是不变的。
        # 从卷基层到全连接层的维度转换

        x = F.relu(self.fc1(x))
        x = F.relu(self.fc2(x))
        x = self.fc3(x)
        return x

IMG_MEAN = [0.485, 0.456, 0.406]
IMG_STD = [0.229, 0.224, 0.225]

net = Net()  # 初始化一个卷积神经网络leNet-
train_data = MyDataset(txt=root + 'num.txt', transform=transforms.Compose([

    transforms.Resize((32, 32)),
    # 将图片缩放到指定大小(h,w)或者保持长宽比并缩放最短的边到int大小


    transforms.CenterCrop(32),
    transforms.ToTensor()])
                       )

train_loader = DataLoader(dataset=train_data, batch_size=227, shuffle=True,drop_last=True)
# batch_size:从样本中取多少张,每一次epoch都会输入batch_size张
print('num_of_trainData:', len(train_data))


def trainandsave():
    # 神经网络结构
    print('h')
    net = Net()
    optimizer = optim.SGD(net.parameters(), lr=0.001, momentum=0.9)  # 学习率为0.001
    criterion = nn.CrossEntropyLoss()  # 损失函数也可以自己定义,我们这里用的交叉熵损失函数
    # 训练部分

    for epoch in range(10):  # 训练的数据量为10个epoch,每个epoch为一个循环
        # 每个epoch要训练所有的图片,每训练完成200张便打印一下训练的效果(loss值)

        running_loss = 0.0  # 定义一个变量方便我们对loss进行输出

        for i, data in enumerate(train_loader, 0):  # 这里我们遇到了第一步中出现的trailoader,代码传入数据
            # enumerate是python的内置函数,既获得索引也获得数据
            # get the inputs

            inputs, labels = data  # data是从enumerate返回的data,包含数据和标签信息,分别赋值给inputs和labels

            # wrap them in Variable
            inputs, labels = Variable(inputs), Variable(labels)  # # 转换数据格式用Variable

            optimizer.zero_grad()  # 梯度置零,因为反向传播过程中梯度会累加上一次循环的梯度

            # forward + backward + optimize
            outputs = net(inputs)  # 把数据输进CNN网络net
            loss = criterion(outputs, labels)  # 计算损失值
            loss.backward()  # loss反向传播
            optimizer.step()  # 反向传播后参数更新
            running_loss += loss.item()  # loss累加
            if i % 9 == 1:
                print('[%d, %5d] loss: %.3f' %
                      (epoch + 1, i + 1, running_loss / 10))  # 平均损失值
                running_loss = 0.0  # 这一个结束后,就把running_loss归零,

    print('Finished Training')
    # 保存神经网络
    torch.save(net, 'net.pkl')
    # 保存整个神经网络的结构和模型参数
    torch.save(net.state_dict(), 'net_params.pkl')


if __name__ == '__main__':
    trainandsave()

记住net的前向传播函数要return x



版权声明:本文为qq_41358574原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。