ML2021_Spring_HW02心得

作业1 Phoneme Classification

助教视频讲解

本次作业助教的视频讲解(需要翻墙)
课程作业代码和作业PPT

本次作业的目的

  1. 学习一个基本的神经网络的搭建,调参过程
  2. 学习pytorch的使用。
  3. 将simple baseline模型调整,使得损失进一步下降。

任务说明

本次作业需要做的是一个phoneme的分类任务,这是一个39分类的任务,输入是一段语音信号,经过一些特征处理等操作(例如FFT等),提取需要的特征,进而进行接下来的分类任务。
在这里插入图片描述

sample code 分析

先说一下整个数据被处理的过程。输入数据train的维度为:1229932×429(样本数×特征数,特征用词不一定准确),所以,神经网络的第一层输入的维度为429。之后,由于VAI_RATIO=0.2,所以validation_set为245987×429,train_set的维度为983945×429。由于BATCH_SIZE的大小为64,所以经过dataloader处理后每个Batch的为64×429。

数据分析

如果下载到ML2021_Spring的课件,助教是有给提供样例的。
本文所用的数据集可以到它给的Kaggle链接上去下载,直接下载到的课件里是没有附带数据集的。
直接下载下来的数据集包含三个文件。

在这里插入图片描述

数据准备

.npy文件是numpy专用的二进制文件。
保存和加载可以直接用numpy的处理函数。

import numpy as np
data_root='./timit_11/'
train=np.load(data_root+'train_11.npy')
train_label=np.load(data_root+'train_label_11.npy')
test=np.load(data_root+'test+11.npy')

创建dataset以及data loader

这一步的主要目的是为了将ndarray转换成Tensor,然后用pytorch自带的Dataloader将dataset按batchsize划分成一个个batch。将数据集处理成dataset的形式,这个函数一般需要自己定义。该sample code划分validation的方式是取训练集中一定比例的数据。两步处理的方式:

from torch.utils.data import Dataset

#Class TIMITDataset 继承了torch里面的Dataset
#在这个function中define了三个函数,初始化,获取数据,以及获取数据长度的变量。
#下面的train_set 以及val_set都是Dataset类型
class TIMITDataset(Dataset):
    def __init__(self,X,y=None):
        self.data=torch.from_numpy(X).float()  #creates a Tensor from a numpy.ndarray
        if y is not None:
            y=y.astype(np.int)
            self.label=torch.LongTensor(y) #tensor直接不可以转换为longtensor,必须先转换为ndarray,再转换为longtensor
        else:
            self.label=None
VAL_RATIO = 0.2

percent = int(train.shape[0] * (1 - VAL_RATIO))
train_x, train_y, val_x, val_y = train[:percent], train_label[:percent], train[percent:], train_label[percent:]
print('Size of training set: {}'.format(train_x.shape))
print('Size of validation set: {}'.format(val_x.shape))


    def __getitem__(self, idx):
        if self.label is not None:
            return self.data[idx],self.label[idx]
        else:
            return self.data[idx]

    def __len__(self):
        return len(self.data)

#Split the labeled data into a training set and a validation set.

# Create a data loader from the dataset.
BATCH_SIZE=64
from torch.utils.data import DataLoader
train_set=TIMITDataset(train_x,train_y)
val_set=TIMITDataset(val_x,val_y)
train_loader=DataLoader(train_set,batch_size=BATCH_SIZE,shuffle=True) #only shuffle the training data
val_loader=DataLoader(val_set,batch_size=BATCH_SIZE,shuffle=True)

这里有必要介绍一下dataloader这个函数。

Data loader. Combines a dataset and a sampler, and provides an iterable over the given dataset.
数据加载程序。组合数据集和采样器,并提供给定数据集的可迭代对象。
dataset (Dataset) – dataset from which to load the data.
batch_size (int, optional) – how many samples per batch to load (default: 1).
shuffle (bool, optional) – set to True to have the data reshuffled at every epoch (default: False).

Create Model

Sample code给的是一个3个layer,3个act_fn的神经网络。Classifier可以直接继承nn.Module

class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()
        self.layer1 = nn.Linear(429, 1024)
        self.layer2 = nn.Linear(1024, 512)
        self.layer3 = nn.Linear(512, 128)
        self.out = nn.Linear(128, 39) 

        self.act_fn = nn.Sigmoid()

    def forward(self, x):
        x = self.layer1(x)
        x = self.act_fn(x)

        x = self.layer2(x)
        x = self.act_fn(x)

        x = self.layer3(x)
        x = self.act_fn(x)

        x = self.out(x)
        
        return x

配置训练参数

个人觉得把有关训练参数,例如epoch,batch_size,learning_rate等写在一个config里比较好,HW01就是这样写的。方便之后调整

#cuda可用就用GPU
def get_device():
  return 'cuda' if torch.cuda.is_available() else 'cpu'
#这个函数应该是都一样的,为了之后的reproducibility,固定随机数种子
def same_seeds(seed):
    torch.manual_seed(seed)
    if torch.cuda.is_available():
        torch.cuda.manual_seed(seed)
        torch.cuda.manual_seed_all(seed)  
    np.random.seed(seed)  
    torch.backends.cudnn.benchmark = False
    torch.backends.cudnn.deterministic = True

same_seeds(0)

# get device 
device = get_device()
print(f'DEVICE: {device}')

# training parameters
num_epoch = 20               # number of training epoch
learning_rate = 0.0001       # learning rate

# the path where checkpoint saved
model_path = './model.ckpt'

# create model, define a loss function, and optimizer
model = Classifier().to(device)
criterion = nn.CrossEntropyLoss() 
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)

训练过程

best_acc = 0.0
for epoch in range(num_epoch):
    train_acc = 0.0
    train_loss = 0.0
    val_acc = 0.0
    val_loss = 0.0

    # training
    model.train() # set the model to training mode
    for i, data in enumerate(train_loader):
        inputs, labels = data
        inputs, labels = inputs.to(device), labels.to(device)
        optimizer.zero_grad() 
        outputs = model(inputs) 
        batch_loss = criterion(outputs, labels)  #criterion=nn.CrossEntropyLoss()
        _, train_pred = torch.max(outputs, 1) # get the index of the class with the highest probability
        #torch.max  0代表每列的最大值,1代表每一行的最大值。
        batch_loss.backward()  #后向传播
        optimizer.step()       #参数更新

        train_acc += (train_pred.cpu() == labels.cpu()).sum().item()
        train_loss += batch_loss.item()

    # validation
    if len(val_set) > 0:
        model.eval() # set the model to evaluation mode
        with torch.no_grad():
            for i, data in enumerate(val_loader):
                inputs, labels = data
                inputs, labels = inputs.to(device), labels.to(device)
                outputs = model(inputs)
                batch_loss = criterion(outputs, labels) 
                _, val_pred = torch.max(outputs, 1) 
            
                val_acc += (val_pred.cpu() == labels.cpu()).sum().item() # get the index of the class with the highest probability
                val_loss += batch_loss.item()

            print('[{:03d}/{:03d}] Train Acc: {:3.6f} Loss: {:3.6f} | Val Acc: {:3.6f} loss: {:3.6f}'.format(
                epoch + 1, num_epoch, train_acc/len(train_set), train_loss/len(train_loader), val_acc/len(val_set), val_loss/len(val_loader)
            ))

            # if the model improves, save a checkpoint at this epoch
            if val_acc > best_acc:
                best_acc = val_acc
                torch.save(model.state_dict(), model_path)
                print('saving model with acc {:.3f}'.format(best_acc/len(val_set)))
    else:
        print('[{:03d}/{:03d}] Train Acc: {:3.6f} Loss: {:3.6f}'.format(
            epoch + 1, num_epoch, train_acc/len(train_set), train_loss/len(train_loader)
        ))

# if not validating, save the last epoch
if len(val_set) == 0:
    torch.save(model.state_dict(), model_path)
    print('saving model at last epoch')

测试以及保存过程

# create testing dataset
test_set = TIMITDataset(test, None)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=False)

# create model and load weights from checkpoint
model = Classifier().to(device)
model.load_state_dict(torch.load(model_path))


# Make prediction.

# In[ ]:


predict = []
model.eval() # set the model to evaluation mode
with torch.no_grad():
    for i, data in enumerate(test_loader):
        inputs = data
        inputs = inputs.to(device)
        outputs = model(inputs)
        _, test_pred = torch.max(outputs, 1) # get the index of the class with the highest probability

        for y in test_pred.cpu().numpy():
            predict.append(y)


# Write prediction to a CSV file.
# 
# After finish running this block, download the file `prediction.csv` from the files section on the left-hand side and submit it to Kaggle.

# In[ ]:


with open('prediction.csv', 'w') as f:
    f.write('Id,Class\n')
    for i, y in enumerate(predict):
        f.write('{},{}\n'.format(i, y))

Adaptive learning rate

在这里我想总结一下李宏毅老师的前几课类神经网络训练不起来怎么办

optimizer的问题

相关课程链接放到这里New Optimizers for Deep Learning
首先,方法有哪些?

1. SGD
2. SGD with momentum(SGDM)
3. Adagrad
4. RMSProp
5. Adam

Some Notations:
在这里插入图片描述

图1

SGD(1847)

在这里插入图片描述

图2

SGDM(1986)

在这里插入图片描述

图3

在这里插入图片描述

图4

Adagrad(2011)

在这里插入图片描述

图5

RMSProp(2013)

在这里插入图片描述

图6

改进版的Adagrad

Adam(2015)

在这里插入图片描述

图7
AdamSGD
fast training ,large generalization gap,unstablestable,little generalization gap,better convergence

SWATS(2017)

在这里插入图片描述

图8

AMSGrad(2018)

在这里插入图片描述

AdaBound(2017)

在这里插入图片描述
在这里插入图片描述

Cyclical LR(2017)

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

RAdam(2020)

在这里插入图片描述
右下角的是warm-up的learning rate的曲线

在这里插入图片描述

Lookahead

在这里插入图片描述
对比
在这里插入图片描述
在这里插入图片描述

L2 regularization

在这里插入图片描述
在这里插入图片描述

Someting helps optimization

在这里插入图片描述
在这里插入图片描述

Batch的影响

在这里插入图片描述
shuffle 等于true是指每一个epoch分的batch都不一样。

small batchlarge batch
long time for cooldown but powerfulshort time for cooldown but noisy

1. Large batch size does not require longer time to compute gradient

在这里插入图片描述
在这里插入图片描述
60次Batch_Size为1000跑完一个epoch的时间较短。

2.Smaller batch size has better performance

在这里插入图片描述

3.Small batch is better on testing data

在这里插入图片描述
这个图给出了一种解释,为什么小的batchsize会对test有帮助。首先,我们假设test的loss就是train的loss平移一段。如果train上的loss找到的是一个类似Flat Minima的的点,那么在test上也没有太大的影响。可是如果train上的loss找到的是一个sharp Minima。可以发现,此时在test上取到的是一个非常差的点。我们说,large batch一般来说很容易让train上的loss找到sharp Minima这种点,而small batch很容易让loss找到flat minma这种点,所以small batch对于test来说是有好处的。不过这只能作为一种解释,不能作为结论。

在这里插入图片描述

4.So,Batch size is a hyperparameter you have to decide

Loss 的影响(为什么要用cross-entropy)

classification 相比于 regression 加入softmax

在这里插入图片描述
Minimizing cross-entropy is equivalent to maximizing likelihood
pytorch的cross—entropy内嵌了softmax

criterion = nn.CrossEntropyLoss() 

在这里插入图片描述

如果初始点在右上角,MSE的loss可能降不下来,因为MSE在右上角的gradient很小。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值