pytorch入门实战(李宏毅hw2_仿_读代码)

这篇文章主要是看看别人的代码怎么写,自己目前对于分类问题还是不太会(菜哭了)

数据集

kaggle

数据地址:
https://www.kaggle.com/competitions/ml2021spring-hw2/data
代码地址:
https://www.kaggle.com/code/lizupeng/notebook4bf3cf8e90

代码

# This Python 3 environment comes with many helpful analytics libraries installed
# It is defined by the kaggle/python Docker image: https://github.com/kaggle/docker-python
# For example, here's several helpful packages to load

import numpy as np # linear algebra
import pandas as pd # data processing, CSV file I/O (e.g. pd.read_csv)

# Input data files are available in the read-only "../input/" directory
# For example, running this (by clicking run or pressing Shift+Enter) will list all files under the input directory

import os
for dirname, _, filenames in os.walk('/kaggle/input'):
    for filename in filenames:
        print(os.path.join(dirname, filename))

# You can write up to 20GB to the current directory (/kaggle/working/) that gets preserved as output when you create a version using "Save & Run All" 
# You can also write temporary files to /kaggle/temp/, but they won't be saved outside of the current session

“”“kaggle经典开头代码,没什么好说的”“”

———————————————分割线——————————————

print('Loading data ...')

data_root = '/kaggle/input/ml2021spring-hw2/timit_11/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')
"""
这里采用的np.load,不是pd
我们的文件形式.npy
ChatGPT:
np.load() 是 NumPy 库中用于加载 NumPy 保存的数组数据的函数。它允许你从磁盘上的 .npy 文件中加载数据并将其转换为 NumPy 数组,以便在 Python 中使用。
numpy.load(file, mmap_mode=None, allow_pickle=True, fix_imports=True, encoding='ASCII')
参数说明:

file: 要加载的 .npy 文件的路径。
mmap_mode:指定文件的内存映射模式。默认为 None,表示不使用内存映射。其他选项包括 'r'(只读模式),'r+'(读写模式)等。
allow_pickle:布尔值,指示是否允许加载包含 Python 对象的 .npy 文件。默认为 True。
fix_imports:布尔值,指示是否自动修复 Python 2 和 Python 3 之间的 pickle 文件中的 import 语句。默认为 True。
encoding:指定文件的编码。默认为 'ASCII'。
"""
print('Size of training data: {}'.format(train.shape))
print('Size of training data: {}'.format(test.shape))

Loading data ...
Size of training data: (1229932, 429)
Size of training data: (451552, 429)

# 定义数据集,经典的三个函数
import torch
from torch.utils.data import Dataset

# 定义数据集
class TIMITDataset(Dataset):
    # 测试节和训练集都需要用这个类
    def __init__(self, X, y=None):
        self.data = torch.from_numpy(X).float()
        # y=None 对应的是测试集
        if y is not None:
            y = y.astype(np.int32)
            # 多分类任务,label是一个long
            self.label = torch.LongTensor(y)
        else:
            self.label = None
            
    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)

# VAL_RATIO为0.2 就是把train、 train_label数据集的80%用于训练,20%用于交叉验证
VAL_RATIO = 0.2

# percent 前80%的数据index
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))

Size of training set: (983945, 429)
Size of validation set: (245987, 429)


# 管理一下内存
import gc

del train, train_label, train_x, train_y, val_x, val_y
gc.collect()
# 检查此刻内存占用情况(值越小越好,一开始是120,删掉上述这些变量后减小为50)


"""定义网络"""
import torch
import torch.nn as nn

class Classifier(nn.Module):
    def __init__(self):
        super(Classifier, self).__init__()
        # 其实这里可以看出,layer1、layer2 、、、、、act_fn、、、、这些都是这个类的全局变量
        # 你定义这些层,如果可以是可以重复使用的
        # 这和nn.Sequential() 不太一样,
        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


# cpu or gpu
def get_device():
    return 'cuda' if torch.cuda.is_available() else 'cpu'

# fix random seed 修改随机数,保证每一次训练结果一样,这段代码不需要背会,用的时候直接cv即可
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)

device = get_device()

# training
num_epoch = 20
learning_rate = 0.0001

# 设置checkpoint的存放位置,其实就是存放最优模型的位置,ckpt是文件类型、写pth也没错
model_path = './model.ckpt'

model = Classifier().to(device)
criterion = nn.CrossEntropyLoss()
# pytorch中如果采用交叉验证的损失函数,那么一定是分类任务,这时候softmax是包含在crossEntropyLoss函数中的,不需要额外调用
optimizer = torch.optim.Adam(model.parameters(), lr=learning_rate)



"""接下来是重点"""
# train
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
    
    model.train()
    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)
        # 取可能性最大的一个,这里的train_pred是用来计算acc精准度的
        _, train_pred = torch.max(outputs, 1)
        batch_loss.backward()
        optimizer.step()
        
        # train_pred
        train_acc += (train_pred.cpu() == labels.cpu()).sum().item()# 此时的train_acc是在计算预测正确的语言的个数,如果当前语言预测正确,则train_acc+1
        train_loss += batch_loss.item()# train_loss用于计算总的训练的loss
        
    if len(val_set) > 0:
        model.eval()
        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()
                val_loss += batch_loss.item()
                
            # 打印每一轮epoch的训练精度、训练loss、验证精度、验证loss
            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)
            ))
            # 这样一来最后保存的模型文件只有一个,且保存的这一个模型文件是精度最高的那一次epoch所训练的模型文件
            if val_acc > best_acc:
                beat_acc = val_acc
                torch.save(model.state_dict(), model_path)
                print('saving model with acc {:.3f}'.format(best_acc/len(val_set)))
    else:# 这个else是给验证集为0时准备的,当我们设置超参VAL_RATIO为0时,验证集为0,就要执行这个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)
        ))
# 这一步也是为了防止没有验证集所写的,
# 如果验证集为0,则不会有最优模型被保存,为防止出bug,设置:当没有验证集时,选取最后一次epoch训练的模型为最优模型并保存
if len(val_set) == 0:
    torch.save(model.state_dict(), model_path)
    print('saving model at last epoch')
"""
我的训练结果:
[001/020] Train Acc: 0.594383 Loss: 1.330665 | Val Acc: 0.628639 loss: 1.211098
saving model with acc 0.000
[002/020] Train Acc: 0.644506 Loss: 1.154064 | Val Acc: 0.660421 loss: 1.101215
saving model with acc 0.000
[003/020] Train Acc: 0.672217 Loss: 1.052246 | Val Acc: 0.676300 loss: 1.038718
saving model with acc 0.000
[004/020] Train Acc: 0.691347 Loss: 0.983103 | Val Acc: 0.685154 loss: 1.001852
saving model with acc 0.000
[005/020] Train Acc: 0.705615 Loss: 0.931955 | Val Acc: 0.689301 loss: 0.984177
saving model with acc 0.000
[006/020] Train Acc: 0.716344 Loss: 0.891687 | Val Acc: 0.694516 loss: 0.964627
saving model with acc 0.000
[007/020] Train Acc: 0.725881 Loss: 0.857907 | Val Acc: 0.697720 loss: 0.951889
saving model with acc 0.000
[008/020] Train Acc: 0.733718 Loss: 0.829495 | Val Acc: 0.696687 loss: 0.949866
saving model with acc 0.000
[009/020] Train Acc: 0.741151 Loss: 0.803701 | Val Acc: 0.699374 loss: 0.944832
saving model with acc 0.000
[010/020] Train Acc: 0.748050 Loss: 0.781106 | Val Acc: 0.697773 loss: 0.946494
saving model with acc 0.000
[011/020] Train Acc: 0.753793 Loss: 0.760380 | Val Acc: 0.702830 loss: 0.938236
saving model with acc 0.000
[012/020] Train Acc: 0.759404 Loss: 0.741234 | Val Acc: 0.700452 loss: 0.945627
saving model with acc 0.000
[013/020] Train Acc: 0.764573 Loss: 0.723574 | Val Acc: 0.702159 loss: 0.942118
saving model with acc 0.000
[014/020] Train Acc: 0.769471 Loss: 0.707325 | Val Acc: 0.704427 loss: 0.936154
saving model with acc 0.000
[015/020] Train Acc: 0.773687 Loss: 0.691314 | Val Acc: 0.701736 loss: 0.945713
saving model with acc 0.000
[016/020] Train Acc: 0.778676 Loss: 0.676633 | Val Acc: 0.701586 loss: 0.953081
saving model with acc 0.000
[017/020] Train Acc: 0.783107 Loss: 0.662425 | Val Acc: 0.699655 loss: 0.963290
saving model with acc 0.000
[018/020] Train Acc: 0.786394 Loss: 0.649180 | Val Acc: 0.700078 loss: 0.957681
saving model with acc 0.000
[019/020] Train Acc: 0.790645 Loss: 0.636623 | Val Acc: 0.699732 loss: 0.964269
saving model with acc 0.000
[020/020] Train Acc: 0.794713 Loss: 0.623686 | Val Acc: 0.694821 loss: 0.981714
saving model with acc 0.000

精准度不是很高,用的cpu训练,耗时将近一个半小时(哭)
"""

# 个人的代码就运行到这里,下面的代码没有亲自运行,大家自行看看把,主要是测试集的处理
# ---------------------------分割线-------------------------------------------------
# create testing dataset
test_set = TIMITDataset(test, None)
test_loader = DataLoader(test_set, batch_size=BATCH_SIZE, shuffle=False)
# del test_set # 删除不再需要的大型变量,防止内存爆掉

# create model and load weights from checkpoint 加载保存的模型
model = Classifier().to(device)
model.load_state_dict(torch.load(model_path))


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(): # 这里之所以使用for是因为,预测值不止一个(因为模型是按照batch加载的,训练也是每batch个音频一起训练,所以得到的应该是batch个预测值)
            predict.append(y)
with open('prediction.csv', 'w') as f:
    f.write('Id,Class\n')
    for i, y in enumerate(predict):
        f.write('{},{}\n'.format(i, y))
  • 5
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值