使用PyTorch实现鸟类音频检测卷积网络模型(下)

简介: 使用PyTorch实现鸟类音频检测卷积网络模型

模型

我为我的模型设置了必要的辅助函数,以便以后进行训练:

class ModelBase(nn.Module):
    # defines mechanism when training each batch in dl
    def train_step(self, batch):
        xb, labels = batch
        outs = self(xb)
        loss = F.cross_entropy(outs, labels)
        return loss
    # similar to `train_step`, but includes acc calculation & detach
    def val_step(self, batch):
        xb, labels = batch
        outs = self(xb)
        loss = F.cross_entropy(outs, labels)
        acc = accuracy(outs, labels)
        return {'loss': loss.detach(), 'acc': acc.detach()}
    # average out losses & accuracies from validation epoch
    def val_epoch_end(self, outputs):
        batch_loss = [x['loss'] for x in outputs]
        batch_acc = [x['acc'] for x in outputs]
        avg_loss = torch.stack(batch_loss).mean()
        avg_acc = torch.stack(batch_acc).mean()
        return {'avg_loss': avg_loss, 'avg_acc': avg_acc}
    # print all data once done
    def epoch_end(self, epoch, avgs, test=False):
        s = 'test' if test else 'val'
        print(f'Epoch #{epoch + 1}, {s}_loss:{avgs["avg_loss"]}, {s}_acc:{avgs["avg_acc"]}')

定义多个函数,以后可以使用这些函数训练继承这个类的PyTorch模型。


def accuracy(outs, labels):
    _, preds = torch.max(outs, dim=1)
    return torch.tensor(torch.sum(preds == labels).item() / len(preds))

这个函数在上述类的val_step函数中被用来确定验证dataloader上模型的%准确性。

并定义用于拟合/训练模型和在验证数据集上测试模型的主要功能

@torch.no_grad()
def evaluate(model, val_dl):
    # eval mode
    model.eval()
    outputs = [model.val_step(batch) for batch in val_dl]
    return model.val_epoch_end(outputs)
def fit(epochs, lr, model, train_dl, val_dl, opt_func=torch.optim.Adam):
    torch.cuda.empty_cache()
    history = []
    # define optimizer
    optimizer = opt_func(model.parameters(), lr)
    # for each epoch...
    for epoch in range(epochs):
        # training mode
        model.train()
        # (training) for each batch in train_dl...
        for batch in tqdm(train_dl):
            # pass thru model
            loss = model.train_step(batch)
            # perform gradient descent
            loss.backward()
            optimizer.step()
            optimizer.zero_grad()
        # validation
        res = evaluate(model, val_dl)
        # print everything useful
        model.epoch_end(epoch, res, test=False)
        # append to history
        history.append(res)
    return history

最后,这是我们等待已久的简单CNN模型:

class Classifier(ModelBase):
    def __init__(self):
        super().__init__()                                     # 1 x 128 x 24
        self.conv1 = nn.Conv2d(1, 4, kernel_size=3, padding=1) # 4 x 128 x 24
        self.conv2 = nn.Conv2d(4, 8, kernel_size=3, padding=1) # 8 x 128 x 24
        self.bm1 = nn.MaxPool2d(2)                             # 8 x 64 x 12
        self.conv3 = nn.Conv2d(8, 8, kernel_size=3, padding=1) # 8 x 64 x 12
        self.bm2 = nn.MaxPool2d(2)                             # 8 x 32 x 6
        self.fc1 = nn.Linear(8*32*6, 64)
        self.fc2 = nn.Linear(64, 2)
    def forward(self, xb):
        out = F.relu(self.conv1(xb))
        out = F.relu(self.conv2(out))
        out = self.bm1(out)
        out = F.relu(self.conv3(out))
        out = self.bm2(out)
        out = torch.flatten(out, 1)
        out = F.relu(self.fc1(out))
        out = self.fc2(out)
        return out

我使用了多个卷积层,正如我们之前的理论推断所建议的那样,我们的模型使用了一些最大池化层,然后使用一个非常简单的全连接网络来进行实际的分类。令人惊讶的是,这个架构后来表现得相当好,甚至超过了我自己的预期。

利用GPU

几乎每个人都需要GPU来训练比一般的前馈神经网络更复杂的东西。幸运的是,PyTorch让我们可以很容易地利用现有GPU的能力。首先,我们将我们的cuda设备定义为关键词设备,以便更容易访问:

device = 'cuda' if torch.cuda.is_available() else 'cpu'

 

我们还确保如果没有GPU, CPU会被使用。

这里还有另一个技巧:

torch.backends.cudnn.benchmark = True

这可以帮助提高你的训练速度(如果你的输入在大小/形状上没有变化)

显然,你可以“告诉”PyTorch在一次又一次的训练中优化自己,只要训练输入在大小和形状上保持不变。它会知道为你的特定硬件(GPU)使用最快的算法。!

然后我们定义帮助函数来移动dataloaders、tensors和我们的模型到我们的GPU设备。

def to_device(data, device):
    """Move tensor(s) to chosen device"""
    if isinstance(data, (list, tuple)):
        return [to_device(x, device) for x in data]
    return data.to(device, non_blocking=True)
class DeviceDataLoader():
    """Wrap a dataloader to move data to a device"""
    def __init__(self, dl, device):
        self.dl = dl
        self.device = device
    def __iter__(self):
        """Yield a batch of data after moving it to device"""
        for b in self.dl:
            yield to_device(b, self.device)
    def __len__(self):
        """Number of batches"""
        return len(self.dl)

训练

使用我们的设备辅助功能,我们将一切移动到我们的GPU如下:

train_dl = DeviceDataLoader(train_dl, device)
val_dl = DeviceDataLoader(val_dl, device)
model = to_device(Classifier(), device)

我们还指定了我们的学习速度和我们的训练次数,我花了很长时间来找到一个好的值。

lr = 1e-5
epochs = 8

在进行任何训练之前,我们会发现模型的表现:

history = [evaluate(model, val_dl)]
[{'avg_loss': tensor(0.7133, device='cuda:0'), 'avg_acc': tensor(0.6042)}]

很显然,我们在开始时的准确性上有点幸运,但经过多次试验,最终结果即使不相同,也会非常相似。

接下来,我们使用之前定义的fit函数来训练我们的简单分类器模型实例:

history += fit(epochs, lr, model, train_dl, val_dl)
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #1, val_loss:0.6354132294654846, val_acc:0.7176136374473572
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #2, val_loss:0.6065077781677246, val_acc:0.7439352869987488
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #3, val_loss:0.56722491979599, val_acc:0.77376788854599
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #4, val_loss:0.5528884530067444, val_acc:0.7751822471618652
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #5, val_loss:0.5130119323730469, val_acc:0.8004600405693054
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #6, val_loss:0.4849482774734497, val_acc:0.8157732486724854
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #7, val_loss:0.4655478596687317, val_acc:0.8293880224227905
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #8, val_loss:0.4765000343322754, val_acc:0.8155447244644165

在发现精确度有一点下降后,我决定再训练一点点,让模型重定向回到正确的方向:

history += fit(3, 1e-6, model, train_dl, val_dl)
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #1, val_loss:0.4524107873439789, val_acc:0.8329823613166809
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #2, val_loss:0.44666698575019836, val_acc:0.8373703360557556
HBox(children=(FloatProgress(value=0.0, max=352.0), HTML(value='')))
 Epoch #3, val_loss:0.4442901611328125, val_acc:0.8412765860557556

忽略“HBox”工件,这是tqdm提供的,请多关注准确性!

总结一下,以下是我们过去11个时期的训练统计数据:

plt.plot([x['avg_loss'] for x in history])
plt.title('Losses over epochs')
plt.xlabel('epochs')
plt.ylabel('loss')
plt.show()

640.png

plt.plot([x['avg_acc'] for x in history])
plt.title('Accuracy over epochs')
plt.xlabel('epochs')
plt.ylabel('acc')
plt.show()

640.png

总的来说,我们的模型训练得相当好,从它的外观来看,我们可能已经为我们的模型的损失找到了一个相对最小的值。

等等,一个更复杂的模型或者使用不同的转换怎么样?

相信我,在我的simple Classifier()第一次尝试成功之后不久,我也尝试过这两种方法。我决定不包括这两个细节,因为我发现他们的结果实际上比我们已经取得的结果更糟糕,这很奇怪。

对于额外的谱图转换,我尝试了随机时移和噪声注入。长话短说,它似乎根本没有提高验证的准确性。此后,我认为是这样,因为数据集规范明确表示,所有啾啾将位于中间的录音,因此随机变化的光谱图的目的允许更好的模型泛化实际上可能已经作为损害的表现。然而,我还没有尝试过随机噪声注入。

我还尝试训练一个ResNet50模型,希望进一步提高验证的准确性。这是最令人难以置信的部分:我的模型从来没有超过50%的准确率!直到今天我写这篇文章的时候,我还不确定我做错了什么,所以如果其他人能看看笔记本并帮助我,我很高兴收到任何建议!

结论

总而言之,这是一个真正有趣的努力,花一些时间进行研究。首先,我得重新审视我去年夏天调查过的东西,无可否认,这有一种怀旧的感觉。更重要的是,我们学习了如何实现一个很可能用于真实场景的PyTorch数据集类,在真实场景中,数据不一定像您预期的那样设置。最后,最终的验证分数为84%,对于我即兴创建的如此简单的网络架构来说,这是相当整洁的!

相关实践学习
在云上部署ChatGLM2-6B大模型(GPU版)
ChatGLM2-6B是由智谱AI及清华KEG实验室于2023年6月发布的中英双语对话开源大模型。通过本实验,可以学习如何配置AIGC开发环境,如何部署ChatGLM2-6B大模型。
目录
相关文章
|
5月前
|
机器学习/深度学习 PyTorch TensorFlow
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic,深度学习探索者。深耕TensorFlow与PyTorch,分享框架对比、性能优化与实战经验,助力技术进阶。
|
6月前
|
机器学习/深度学习 存储 PyTorch
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
Neural ODE将神经网络与微分方程结合,用连续思维建模数据演化,突破传统离散层的限制,实现自适应深度与高效连续学习。
474 3
Neural ODE原理与PyTorch实现:深度学习模型的自适应深度调节
|
5月前
|
边缘计算 人工智能 PyTorch
130_知识蒸馏技术:温度参数与损失函数设计 - 教师-学生模型的优化策略与PyTorch实现
随着大型语言模型(LLM)的规模不断增长,部署这些模型面临着巨大的计算和资源挑战。以DeepSeek-R1为例,其671B参数的规模即使经过INT4量化后,仍需要至少6张高端GPU才能运行,这对于大多数中小型企业和研究机构来说成本过高。知识蒸馏作为一种有效的模型压缩技术,通过将大型教师模型的知识迁移到小型学生模型中,在显著降低模型复杂度的同时保留核心性能,成为解决这一问题的关键技术之一。
|
5月前
|
机器学习/深度学习 数据采集 人工智能
深度学习实战指南:从神经网络基础到模型优化的完整攻略
🌟 蒋星熠Jaxonic,AI探索者。深耕深度学习,从神经网络到Transformer,用代码践行智能革命。分享实战经验,助你构建CV、NLP模型,共赴二进制星辰大海。
|
6月前
|
机器学习/深度学习 传感器 算法
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
【无人车路径跟踪】基于神经网络的数据驱动迭代学习控制(ILC)算法,用于具有未知模型和重复任务的非线性单输入单输出(SISO)离散时间系统的无人车的路径跟踪(Matlab代码实现)
405 2
|
6月前
|
机器学习/深度学习 人工智能 算法
卷积神经网络深度解析:从基础原理到实战应用的完整指南
蒋星熠Jaxonic带你深入卷积神经网络(CNN)核心技术,从生物启发到数学原理,详解ResNet、注意力机制与模型优化,探索视觉智能的演进之路。
565 11
|
6月前
|
机器学习/深度学习 并行计算 算法
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
【CPOBP-NSWOA】基于豪冠猪优化BP神经网络模型的多目标鲸鱼寻优算法研究(Matlab代码实现)
146 8
|
6月前
|
机器学习/深度学习 传感器 数据采集
【故障识别】基于CNN-SVM卷积神经网络结合支持向量机的数据分类预测研究(Matlab代码实现)
【故障识别】基于CNN-SVM卷积神经网络结合支持向量机的数据分类预测研究(Matlab代码实现)
411 0
|
12月前
|
机器学习/深度学习 JavaScript PyTorch
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体
生成对抗网络(GAN)的训练效果高度依赖于损失函数的选择。本文介绍了经典GAN损失函数理论,并用PyTorch实现多种变体,包括原始GAN、LS-GAN、WGAN及WGAN-GP等。通过分析其原理与优劣,如LS-GAN提升训练稳定性、WGAN-GP改善图像质量,展示了不同场景下损失函数的设计思路。代码实现覆盖生成器与判别器的核心逻辑,为实际应用提供了重要参考。未来可探索组合优化与自适应设计以提升性能。
1006 7
9个主流GAN损失函数的数学原理和Pytorch代码实现:从经典模型到现代变体

热门文章

最新文章

推荐镜像

更多