动手深度学习(Pytorch)之路---第一次打卡

引言

首先,在这里感谢Datawhale提供的免费学习的机会,感谢各位老师和助教的努力。在下小白一枚,也没有写过博客,借此机会,锻炼自己的写作。希望自己能够不断坚持,完成这两周的学习任务。短期目标:能够熟练的使用pytorch基础功能,构建完整的神经网络模型,发论文,走上人生巅峰!!!
第一次打卡的内容主要分为两部分:构建基础的pytorch模型(线性回归和分类模型)及基础RNN模型。

线性回归及分类模型

有监督模型中,回归问题和分类问题是两种常见的问题。回归和分类的区别在于输出变量的类型。回归问题的输出个数为1,并且其数值是连续的;分类问题的输出个数是类别数,代表的是各类别的得分或者概率,是离散的。事实上,在实际操作中,回归问题和分类问题也可以互相转化(分类问题回归化:逻辑回归;回归问题分类化:年龄预测问题>>>年龄段分类问题)。

线性回归

直接上栗子!!!房价预测问题:假设价格只取决于房屋状况的两个因素,即面积(平方米)和房龄(年)。因此,我们需要建立一个模型,研究房价和这两个因素(也可以叫做特征)存在的数学关系。线性回归的思想很直接,直接将他们考虑为线性关系。即模型为: W a r e a ∗ a r e a + W a g e ∗ a g e + b W_{area} * area + W_{age} * age + b Wareaarea+Wageage+b
因为模型比较简单,在此示例中,使用的数据是我们自己构造的。损失函数使用的是均方误差: L o s s = 1 n ∑ 1 n ( y i − y ^ i ) 2 Loss = \frac{1}{n}\sum_{1}^{n}(y_{i} - \hat{y}_{i})^{2} Loss=n11n(yiy^i)2 优化函数使用的是随机梯度下降: ( w , b ) ← ( w , b ) − η ⋅ ( ∂ ∂ w L o s s ( w , b ) , ∂ ∂ b L o s s ( w , b ) ) (w, b) \leftarrow (w, b) - \eta \cdot( \frac{\partial}{\partial w}Loss(w,b), \frac{\partial}{\partial b}Loss(w,b)) (w,b)(w,b)η(wLoss(w,b),bLoss(w,b))其中, η \eta η是学习率。具体代码如下:

import torch
from torch import nn
import numpy as np
import torch.utils.data as Data
from torch.nn import init
import torch.optim as optim

torch.manual_seed(1) # 设置随机种子,调用随机函数时,相同的随机种子会产生相同的随机数,便于试验复现

# 设置模型的一些超参数
num_inputs = 2  # 输入特征数
num_examples = 1000 # 样本个数
batch_size = 10 # 每次训练使用的数据批数
learning_rate = 0.03 # 定义学习率
num_epochs = 3 # 定义训练次数

###### 下面的代码是为了生成数据集 ######
# 假设的真实参数,模型训练参数越接近则表明模型越好
true_w = [2, -3.4] 
true_b = 4.2
# 使用随机函数产生形状为(1000,2)的输入数据,代表1000个房屋的面积和房龄
features = torch.tensor(np.random.normal(0, 1, (num_examples, num_inputs)), dtype=torch.float)
# 计算房价
labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
# 使用随机函数,产生噪音,为了使数据更真实
labels += torch.tensor(np.random.normal(0, 0.01, size=labels.size()), dtype=torch.float)

###### 下面是模型定义 ######
# 将数据集放入dataset中,便于模型调用
dataset = Data.TensorDataset(features, labels)

# put dataset into DataLoader
data_iter = Data.DataLoader(
    dataset=dataset,            # torch TensorDataset format
    batch_size=batch_size,      # mini batch size
    shuffle=True,               # whether shuffle the data or not
    num_workers=2,              # read data in multithreading # window下会报错,注释掉即可
)

class LinearNet(nn.Module):
    def __init__(self, n_feature):
        super(LinearNet, self).__init__()      # call father function to init 
        self.linear = nn.Linear(n_feature, 1)  # function prototype: `torch.nn.Linear(in_features, out_features, bias=True)`

    def forward(self, x):
        y = self.linear(x)
        return y
        
net = LinearNet(num_inputs) # 初始化模型
# print(net) # 可以打印模型,查看模型结构是否正确

###### 下面是参数初始化 ######
init.normal_(net[0].weight, mean=0.0, std=0.01)
init.constant_(net[0].bias, val=0.0)
# 定义损失函数
loss = nn.MSELoss()
# 定义优化函数
optimizer = optim.SGD(net.parameters(), lr=learning_rate)

###### 下面开始训练 ######
for epoch in range(1, num_epochs + 1):
    for X, y in data_iter:
        output = net(X) # 这里调用模型
        l = loss(output, y.view(-1, 1)) # 计算损失
        optimizer.zero_grad() # 梯度清零
        l.backward() # 梯度反向传播
        optimizer.step() 
    print('epoch %d, loss: %f' % (epoch, l.item()))

###### 训练结束,查看模型训练后的参数 ######
dense = net[0]
print(true_w, dense.weight.data)
print(true_b, dense.bias.data)

多层感知机

感知机(全连接神经网络)可以说是神经网络的开门算法,学习感知机的构造是通向神经网络和深度学习的一种重要思想。如下图(图片来源于网络)所示:
具有一个隐藏层的感知机
给定一个小批量样本 X ∈ R n × d X\in \mathbb{R}^{n\times d} XRn×d n n n为批量大小, d d d为输入维度(图中为3),隐藏单元个数为 h h h(图中为3),输出维度为 q q q(图中为3)。假设只有一个隐藏层,隐藏层的输出记为 H H H H ∈ R d × h H\in \mathbb{R}^{d\times h} HRd×h,因此,输入层到隐藏层的权值参数和偏置参数为 W h ∈ R d × h W_{h}\in \mathbb{R}^{d\times h} WhRd×h b h ∈ R 1 × h b_{h}\in \mathbb{R}^{1\times h} bhR1×h,隐藏层到输出层的参数为 W o ∈ R h × q W_{o}\in \mathbb{R}^{h\times q} WoRh×q b o ∈ R 1 × q b_{o}\in \mathbb{R}^{1\times q} boR1×q。其输出 O ∈ R n × q O \in \mathbb{R}^{n \times q} ORn×q的计算如下: H = X W h + b h , H = XW_{h} + b_{h}, H=XWh+bh H ′ = δ ( H ) , {H}' = \delta (H), H=δ(H) O = H ′ W o + b o , O = {H}' W_{o} + b_{o}, O=HWo+bo 其中 δ \delta δ表示的是激活函数。大多数情况下,中间层使用 R e L U ReLU ReLU(只能用于中间层)作为激活函数,输出层使用 s o f t m a x softmax softmax(多分类)或 t a n h tanh tanh(二分类)做为激活函数。
接下来上代码!!!图像分类走起!!!

import torch
from torch import nn
from torch.nn import init
import numpy as np
import sys
sys.path.append("/home/kesci/input")
import d2lzh1981 as d2l

# 设置一些超参数
num_inputs, num_outputs, num_hiddens = 784, 10, 256 # 输入、输出、隐藏单元个数
# 获取训练集
batch_size = 256
num_epochs = 5
learning_rate = 0.5

# 获得训练数据和测试数据
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size,root='/home/kesci/input/FashionMNIST2065')

# 定义模型
class TwoLayerNet(torch.nn.Module):
    def __init__(self, num_inputs, num_hiddens , num_outputs):
        super(TwoLayerNet, self).__init__()
        self.linear1 = nn.Linear(num_inputs, num_hiddens )
        self.linear2 = nn.Linear(num_hiddens , num_outputs)

    def forward(self, x):
        h_relu = self.linear1(x).clamp(min=0)
        y_pred = self.linear2(h_relu)
        return y_pred
# 模型初始化
model = TwoLayerNet(num_inputs, num_hiddens , num_outputs)
# 参数初始化
for params in model.parameters():
    init.normal_(params, mean=0, std=0.01)

# 定义优化器
optimizer = torch.optim.SGD(net.parameters(), lr=learning_rate)
# 定义损失函数
loss = torch.nn.CrossEntropyLoss()
# 开始训练
for t in range(num_epochs):
	train_l_sum, train_acc_sum, n = 0.0, 0.0, 0
    for X, y in train_iter:
	    y_hat= model(x)
	    loss = loss(y_hat, y)
	    
	    if optimizer is not None:
			optimizer.zero_grad()
		elif params is not None and params[0].grad is not None:
			for param in params:
				param.grad.data.zero_()
				
	    loss.backward()
	    if optimizer is None:
			d2l.sgd(params, lr, batch_size)
		else:
			optimizer.step() 
    	train_l_sum += loss.item()
		train_acc_sum += (y_hat.argmax(dim=1) == y).sum().item()
		n += y.shape[0]
	test_acc = evaluate_accuracy(test_iter, net)
	print('epoch %d, loss %.4f, train acc %.3f, test acc %.3f' % (epoch + 1, train_l_sum / n, train_acc_sum / n, test_acc))

文本预处理

自然语言处理(NLP)是深度学习的一大应用方向,文本是一类序列数据。然而,深度神经网络模型只接受数字作为输入,因此,在使用神经网络前,通常需要将文本进行预处理,转化为数字。本节介绍几个常用的预处理步骤。

读入文本

import collections
import re

def read_time_machine():
    with open('timemachine.txt', 'r') as f:
        lines = [re.sub('[^a-z]+', ' ', line.strip().lower()) for line in f] # 清理文本中的特殊字符
    return lines

lines = read_time_machine()
print('# sentences %d' % len(lines)) # sentences 3221

建立字典

def count_corpus(sentences):
	# sentences:[[I am FNLP], [I study pytorch in Datawhale]]
    tokens = [tk for st in sentences for tk in st]
    return collections.Counter(tokens)  # 返回一个字典,记录每个词的出现次数
    
class Vocab(object):
	# 输入:sentences:[[I am FNLP], [I study pytorch in Datawhale]]
    def __init__(self, tokens, min_freq=0, use_special_tokens=True):
    	# 构建字典,统计词出现次数
        counter = count_corpus(tokens) 
        self.token_freqs = list(counter.items())
        self.idx_to_token = []
        # 是否插入特殊标记,通常为True
        if use_special_tokens:
            self.pad, self.bos, self.eos, self.unk = (0, 1, 2, 3)
            self.idx_to_token += ['', '', '', '']
        else:
            self.unk = 0
            self.idx_to_token += ['']
        self.idx_to_token += [token for token, freq in self.token_freqs
                        if freq >= min_freq and token not in self.idx_to_token]
        self.token_to_idx = dict()
        for idx, token in enumerate(self.idx_to_token):
            self.token_to_idx[token] = idx
	# 查看长度
    def __len__(self):
        return len(self.idx_to_token)
	# 根据token(词)获取id
    def __getitem__(self, tokens):
        if not isinstance(tokens, (list, tuple)):
            return self.token_to_idx.get(tokens, self.unk)
        return [self.__getitem__(token) for token in tokens]
	# 根据id 获取对应的词
    def to_tokens(self, indices):
        if not isinstance(indices, (list, tuple)):
            return self.idx_to_token[indices]
        return [self.idx_to_token[index] for index in indices]

总结

暂时先更新到这里,第一次学习的内容还包括语言模型和RNN基础,但是考虑到那两部分的应用并不多,只需要了解就行,而且这次更新的内容也比较多,就留待下次学习LSTM的时候在更新。再次感谢Datawhale提供的这次学习机会。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值