前面我们已经建立好了一个神经网络的分类器Class。
使用PyTorch构建神经网络(详细步骤讲解+注释版) 01-建立分类器类
下面进行数据的读取与模型训练
1 使用PyTorch对数据处理
熟悉基础数据分析的同学应该更习惯使用Pandas库对数据进行处理,此处为了加深对PyTorch的理解,我们尝试使用PyTorch读取数据。这里面用到的包是torch.utils.data.Dataset。
在下面的代码中,分别定义了len方法与getitem方法。这两个方法都是python的内置方法,但是对类并不适用。这里通过重写方法使类也可以调用,并且自定义了getitem方法的输出
from torch.utils.data import Dataset class MnistDataset: def __init__(self, csv_file): self.data = pandas.read_csv(csv_file) pass def __len__(self): return len(self.data) def __getitem__(self, index): # 预期输出的张量制作 label = self.data.iloc[index,0] target = torch.zeros(10) target[label] = 1.0 # 图像数据标准化 image_values = torch.FloatTensor(self.data.iloc[index, 1:].values)/255.0 return label, image_values, target
len方法起到了返回DataFrame大小的作用。
label:获得了指定数据的第一个数值,也就是这个数据的标签;
target:制作了一个维度为10的张量,标签对应的项是1,其他是0。比如,某个手写数据的标签是2,则这个张量是[0, 0, 1, 0, 0, 0, 0, 0, 0, 0]。
image_values:像素输入的值是0-255,这里对像素数据做了标准化,是值位于0-1之间。
在MnistDataset类中,博主也看到有教程为其添加了绘画的功能,这个功能在实现神经网络的过程中,并不会起到实质性作用,但是可能有助于快速查看数据情况,所以我把代码放到这里,很简单大家自行学习就好。
class MnistDataset: def plot_image(self, index): arr = self.data.iloc[index, 1:].values.reshape(28, 28) plt.title("label=" + str(self.data.iloc[index, 0])) plt.imshow(arr, interpolation='none', cmap='Blues') plt.show() 1
可以使用这个功能查看数据集:
mnist_dataset = MnistDataset('数据集地址') mnist_dataset.plot_image(123) 1
2
截至目前,MnistDataset这个类的全部代码为
class MnistDataset: def __init__(self, csv_file): self.data = pandas.read_csv(csv_file) pass def __len__(self): return len(self.data) def __getitem__(self, index): # 预期输出的张量制作 label = self.data.iloc[index, 0] target = torch.zeros(10) target[label] = 1.0 # 图像数据标准化 image_values = torch.FloatTensor(self.data.iloc[index, 1:].values) / 255.0 return label, image_values, target
def plot_image(self, index): arr = self.data.iloc[index, 1:].values.reshape(28, 28) plt.title("label=" + str(self.data.iloc[index, 0])) plt.imshow(arr, interpolation='none', cmap='Blues') plt.show() pass
这是目前我们所完成的内容(蓝色部分位于上一篇博客)
2 模型训练
首先创建一个分类器类
C = Classifier()
在训练过程中,我们可以只训练一轮,也就是训练集中的数据依次传入模型进行训练,也可以训练多轮,即一个数据集都传入一遍之后,在从头重复传入数据进行训练的这个动作。对于描述训练几轮有一个专有名词epochs,在写代码时通常会以这个单词作为变量名。
接下来我们执行三组循环:
epochs = 3 for i in range(epochs): print('training epoch', i+1, 'of', epochs) for label, image_data_tensor, target_tensor in mnist_dataset: C.train(image_data_tensor, target_tensor) 1
在mnist_dataset能够直接取数是因为我们之前定义了getitem方法。以上就是完整的训练过程。在训练时,每当完成一轮或完成10000组数据都会有相应的print(后者来自train方法)。如果我们还想知道这一过程花费的时间,还可以导入time包进行计算。这一部分的完整代码如下。
start_time =time.perf_counter() # 计时开始 C = Classifier() epochs = 3 for i in range(epochs): print('training epoch', i+1, 'of', epochs) for label, image_data_tensor, target_tensor in mnist_dataset: C.train(image_data_tensor, target_tensor) end_time =time.perf_counter() print('完成3个epochs需要的时间是', end_time-start_time)
一般情况下,使用个人电脑进行计算的话,每轮训练一般不超过10分钟。如果购买了Google Colab等付费在线服务器,这一过程还会更快。
3 训练过程可视化
在训练结束之后,如果希望查看训练次数与误差之间的关系,我们可以在Classifier类中定义一个可视化方法。首先在initial下,初始化一个用于记录损失的列表。
class Classifier(nn.Module): def __init__(self): # 用于展示训练进程的计数器和列表 self.counter = 0 self.progress = []
接着在train方法下,每隔10个训练记录一次损失值,每隔10000个输出一次训练个数(也就是对应上面console截图的输出)。
class Classifier(nn.Module): def train(self, inputs, targets): # 进程可视化数据 self.counter += 1 if self.counter % 10 == 0: self.progress.append(loss.item()) pass if self.counter % 10000 == 0: print("counter = ", self.counter) pass
最后,建立一个绘图的方法,使用matplotlib.pyplot(import as plt)绘制散点图。
class Classifier(nn.Module): # 训练进程制图 def plot_progress(self): df = pandas.DataFrame(self.progress, columns=['loss']) df.plot(ylim=(0, 1.0), figsize=(16, 8), alpha=0.1, marker='.', grid=True, yticks=(0, 0.25, 0.5)) plt.show()
这里的一些设置主要是控制绘图细节,比如ylim是坐标轴范围,alpha是透明度,yticks是网格位置等。这一部分如有兴趣也可以对matplotlib.pyplot进行专门学习。
在完善了类的相关方法后,再次进行训练就会自动保存误差数据,训练之后,我们使用:
C.plot_progess() 1
就可以把图绘制出来了。
可以看出,随着训练次数的增加,损失下降还是比较明显的。
本系列文章使用不断迭代优化代码的方式进行撰写,以模块不断对代码进行补充方便大家理解。如果希望获取完整代码文件,直接文末留言或者到个人博客的资源区进行下载即可。完整代码下载链接
下一篇文章将会讲解如何评价模型表现与提升模型准确率