【torch实现鸢尾花识别、手写数字识别】

【torch实现鸢尾花识别、手写数字识别】

注:以下内容由Jupyter Notebook实现

1. 鸢尾花的例子

1.1 载入数据

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F

# 加载数据
def load_iris():
    '''读取鸢尾花数据集'''
    # 从文本中读取数组
    data = np.loadtxt('iris.txt')
    # 打乱顺序
    idx = np.arange(data.shape[0])
    np.random.shuffle(idx)
    data = data[idx]
    print(idx)
    # 归一化
    x = data[:,:-1].astype('float32') # 除去最后一列
    y = data[:,-1].astype('int64') # 取最后一列
    u = x.mean(axis = 0)
    delta = x.std(axis = 0)
    print(u,delta)
    x = (x-u)/delta     # 取标准差,数据标准化使网络更容易收敛, 更快收敛,对识别率有好处
    # 划分训练集,测试集
    spl = int(data.shape[0]*0.9)    # spl划分点
    train_x = x[:spl]
    train_y = y[:spl]
    test_x = x[spl:]
    test_y = y[spl:]
    return train_x, train_y, test_x, test_y
train_x, train_y, test_x, test_y = load_iris()

1.2 定义网络

n_in, n_hid, n_out = 4,3,3
learning_rate = 0.01
batch_size = 1
num_epochs = 100

model = nn.Sequential(nn.Linear(n_in, n_hid),
                      nn.ReLU(inplace= True), 
                      nn.Linear(n_hid, n_out),
                      nn.Softmax(dim = -1))
# inplace为True,将计算得到的值直接覆盖之前的值,产生的计算结果不会有影响。
# 利用in-place计算可以节省内(显)存,同时还可以省去反复申请和释放内存的时间。
# 但是会对原变量覆盖,只要不带来错误就用。参考:http://t.csdn.cn/muYTu

optimizer = torch.optim.SGD(model.parameters(), lr= learning_rate, momentum=0.9)
# 动量momentum=0.9,梯度下降时的折返情况减轻,从而加快训练速度。因为下降的路线更接近同一个方向,因此也可以将学习率增大来加快训练速度。

criterion = nn.CrossEntropyLoss()

1.3 训练网络

for epoch in range(num_epochs):
    # train
    total_loss = 0.
    for i in range(train_x.shape[0]//batch_size):
        x = torch.tensor(train_x[i*batch_size:(i+1)*batch_size])
        y = torch.tensor(train_y[i*batch_size:(i+1)*batch_size])
        out = model(x)
        loss = criterion(out,y)
        #print(loss.item()) 
        total_loss += loss.item() # 一轮的误差累加,每轮会置0

        optimizer.zero_grad()   # 梯度清零
        loss.backward()
        optimizer.step()
    print('epoch = %d, loss = %.3f,' %(epoch,total_loss), end= ' ')

    # test
    with torch.no_grad(): # 测试不需要计算梯度
        x = torch.tensor(test_x)
        y = torch.tensor(test_y)
        out = model(x)
        #print(out)
        pred = torch.argmax(out, axis =1)
        #print(pred)
        print('test error=%.3f'%(torch.mean((pred!=y).float()).item()))

输出:

epoch = 0, loss = 137.227, test error=0.333
epoch = 1, loss = 119.034, test error=0.333
epoch = 2, loss = 116.003, test error=0.333
epoch = 3, loss = 114.791, test error=0.333
epoch = 4, loss = 114.143, test error=0.333
...
epoch = 96, loss = 78.328, test error=0.000
epoch = 97, loss = 78.371, test error=0.000
epoch = 98, loss = 78.312, test error=0.000
epoch = 99, loss = 78.358, test error=0.000

2. 手写数字识别

2.1 定义网络

import numpy as np
import torch
import torch.nn as nn
import torch.nn.functional as F
size = 28	# 图片尺寸28*28

class MLP(nn.Module):
    def __init__(self, n_in, n_hid1, n_hid2, n_out):
        super(MLP, self).__init__()
        self.fc1 = nn.Linear(n_in, n_hid1)
        self.fc2 = nn.Linear(n_hid1, n_hid2)
        self.fc3 = nn.Linear(n_hid2, n_out)
        self.bn1 = nn.BatchNorm1d(n_hid1)
    
    def forward(self, x):
        x = x.view(-1,size*size)
        x = self.fc1(x)
        x = self.bn1(x)
        x = torch.relu(x)
        x = self.fc2(x)
        x = torch.relu(x)
        x = self.fc3(x)
        x = F.softmax(x, dim= 1)
        return x

2.2 生成网络架构,转到GPU中

num_classes = 10
learning_rate = 0.005
batch_size = 32
num_epochs = 50

device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu')
print(device)
model2 = MLP(size*size, 128, 64, num_classes).to(device)
print(model2)
criterion = nn.CrossEntropyLoss().to(device)
optimizer = torch.optim.SGD(model2.parameters(), lr=learning_rate)

输出:

cuda:0
MLP(
  (fc1): Linear(in_features=784, out_features=128, bias=True)
  (fc2): Linear(in_features=128, out_features=64, bias=True)
  (fc3): Linear(in_features=64, out_features=10, bias=True)
  (bn1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)

2.3 使用torchvision加载MNIST数据集

import torchvision

train_dataset = torchvision.datasets.MNIST(root = 'data',
                                           train = True,
                                           transform = torchvision.transforms.ToTensor(),
                                           download = True)
train_loader = torch.utils.data.DataLoader(dataset = train_dataset,
                                           batch_size = batch_size,
                                           shuffle = True)
test_dataset = torchvision.datasets.MNIST(root = 'data',
                                          train = False,
                                          transform = torchvision.transforms.ToTensor(),
                                          download = True)
test_loader = torch.utils.data.DataLoader(dataset=test_dataset,
                                           batch_size=batch_size, 
                                           shuffle=True)

2.4 开始训练网络

for epoch in range(num_epochs):
    # train
    model2.train()   
    train_loss = 0.
    for x,y in train_loader:
        #print(x.is_cuda) # False
        x = x.to(device)
        y = y.to(device)
        outputs = model2(x)       
        loss = criterion(outputs, y)
        train_loss += loss.item()
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
    print('Epoch: %3d/%d, 训练损失: %.6f,' %(epoch+1, num_epochs, 
                                         train_loss/len(train_loader.dataset)*batch_size), end=' ')
    
    # test
    model2.eval()   # 关闭bn和dropout
    with torch.no_grad(): # 不需要计算梯度
        test_loss = 0.
        error = 0.
        for x,y in test_loader:
            x = x.to(device)
            y = y.to(device)
            outputs = model2(x)
            loss = criterion(outputs, y)
            test_loss += loss.item()
            pred = torch.argmax(outputs, axis = 1)
            error += torch.sum((pred!=y).float()).item()
        test_loss /= len(test_loader.dataset)
        error /= len(test_loader.dataset)
        print('测试损失:%.6f, 测试错误率:%.2f%%' %(test_loss, error*100))

    torch.save(model2, 'mlp_mnist.pth')

输出:

Epoch:   1/50, 训练损失: 2.211584, 测试损失:0.064492, 测试错误率:42.37%
Epoch:   2/50, 训练损失: 1.930306, 测试损失:0.057038, 测试错误率:30.64%
Epoch:   3/50, 训练损失: 1.785136, 测试损失:0.053850, 测试错误率:24.34%
Epoch:   4/50, 训练损失: 1.701027, 测试损失:0.051561, 测试错误率:15.53%
Epoch:   5/50, 训练损失: 1.657674, 测试损失:0.050946, 测试错误率:15.07%
...
Epoch:  46/50, 训练损失: 1.487391, 测试损失:0.046716, 测试错误率:2.58%
Epoch:  47/50, 训练损失: 1.487014, 测试损失:0.046676, 测试错误率:2.50%
Epoch:  48/50, 训练损失: 1.486540, 测试损失:0.046680, 测试错误率:2.49%
Epoch:  49/50, 训练损失: 1.485431, 测试损失:0.046679, 测试错误率:2.53%
Epoch:  50/50, 训练损失: 1.485014, 测试损失:0.046652, 测试错误率:2.33%

2.5 模型加载与保存

model3 = torch.load('mlp_mnist.pth')
print('model3:',model3)
print(model3.fc1.weight)

# #模型原本在GPU 0上训练保存,直接载入在没有GPU或GPU编号不一致的机器会出错
model4 = torch.load('mlp_mnist.pth', map_location= 'cpu')
print('model4:',model4)
print(model4.fc1.weight)

输出:

model3: MLP(
  (fc1): Linear(in_features=784, out_features=128, bias=True)
  (fc2): Linear(in_features=128, out_features=64, bias=True)
  (fc3): Linear(in_features=64, out_features=10, bias=True)
  (bn1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
Parameter containing:
tensor([[-0.0230,  0.0144,  0.0335,  ..., -0.0073,  0.0333,  0.0306],
        [-0.0241, -0.0014,  0.0266,  ..., -0.0305, -0.0265,  0.0140],
        [ 0.0292, -0.0196,  0.0259,  ...,  0.0003, -0.0164, -0.0088],
        ...,
        [ 0.0292, -0.0158, -0.0348,  ...,  0.0065, -0.0203, -0.0283],
        [ 0.0342, -0.0273, -0.0317,  ...,  0.0219,  0.0214,  0.0318],
        [-0.0018,  0.0218, -0.0122,  ...,  0.0103, -0.0257, -0.0015]],
       device='cuda:0', requires_grad=True)
model4: MLP(
  (fc1): Linear(in_features=784, out_features=128, bias=True)
  (fc2): Linear(in_features=128, out_features=64, bias=True)
  (fc3): Linear(in_features=64, out_features=10, bias=True)
  (bn1): BatchNorm1d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)
)
Parameter containing:
tensor([[-0.0230,  0.0144,  0.0335,  ..., -0.0073,  0.0333,  0.0306],
        [-0.0241, -0.0014,  0.0266,  ..., -0.0305, -0.0265,  0.0140],
        [ 0.0292, -0.0196,  0.0259,  ...,  0.0003, -0.0164, -0.0088],
...
        [ 0.0292, -0.0158, -0.0348,  ...,  0.0065, -0.0203, -0.0283],
        [ 0.0342, -0.0273, -0.0317,  ...,  0.0219,  0.0214,  0.0318],
        [-0.0018,  0.0218, -0.0122,  ...,  0.0103, -0.0257, -0.0015]],
       requires_grad=True)
  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值