《动手学深度学习》戴口罩的胡萝卜组 - 户建坤 第一次打卡 (线性, Softmax, 多层感知机, 文本预处理, 语言模型, RNN)

线性回归

1. 数据集名词

training set
sample
label
feature

2. 均方差损失函数

均值差的平方损失
(a-b)**2 / 2 在 batch 中求平均, 即 sum / len(batch)
为什么单个要除以 2 ? 其实标准的也可以不 / 2
为什么均方差用的这么多? 好处坏处, 别的?
均方差叫 MSE, mean squared error, RMSE , MAE

3. 随机梯度下降

一个小的启发, 如果 training set 的 batch, 经过梯度回传以后, 再算一遍 loss, 理应比梯度回传前的小, 如果不小, 说明模型拟合 能力不够. 在单个 batch 一定会变小, 不变小说明 lr 取得大了, 整体 loss 均值可能波动或不变, 因为此起彼伏, 到达瓶颈了, 此时应该怎么弄?
这一部分不是太懂.

4. 矢量计算

从 C 语言思维抽离, 或者等价, 只是需要记忆 torch 的向量数据类型和他的操作符, 并且数据角度从单个数升级为向量和矩阵.
下面代码测出可以视为向量本身的操作是忽略不计的, 和 float 近似一样(实际使用中还不知道), 这样快个 1000和10000 倍也是很容易的, 1e6*1e6 也可以不计时间秒出 (0.002), 矩阵操作先不测, 反正就是要准备好矩阵和向量, 然后数学操作, 操作单位不用 for 循环, 而是最小的为 torch.Tensor.

代码片段 A.1
import torch
import time

# init variable a, b as 100000 dimension vector
n = 10000

# use float test real speed
a = torch.randn(n)
b = torch.randn(n)

# a = torch.ones(n)
# b = torch.ones(n)
c = torch.zeros(n)
s = time.time()
for i in range(n):
	c[i] = a[i] * b[i]
print(time.time() - s)
s = time.time()
d = a * b
print(time.time() - s)
print(c, d)

# test *, mul, mm
c2 = torch.mul(a, b)
a3 = torch.randn(2, 3)
b3 = torch.randn(3, 1)
c3 = torch.mm(a3, b3)
print(c2, c3)

讲解:
1.torch.ones(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor

其中 size: 一个数, 或者 ones(2, 3) 就是多维的了; 相似的有 torch.zeros, torch.ones_like(input). 同时注意到 c 类C语言声明的, 而一般像 d 这样直接通过 a, b 两个向量相乘得到, 体现了单元操作是向量/矩阵
2.torch.randn(*size, out=None, dtype=None, layout=torch.strided, device=None, requires_grad=False) → Tensor

其中 size 一样, 可以使 3, 也可以 (4, 5) 就是多维了, 返回值是 N(0,1). 其他的目前先不急, 还有数据类型先不管.
3. 乘号和mul是一致的, 类比 np 拓展的对应位置乘法; 而mm 是 mat-mat-multipy, 严格要求是 23 mm 31 这样的. 剩下的乘法以后再说.

5. 线性数据集随机生成和展示

生成的数据要有噪声加上去, 同时噪声还不能太大. 对 Norm(0, sigma) 的理解, 建立在 sigma 原则上, 大致就是噪声会和 sigma 一个量级, 比如 sigma = 0.01, 那么噪声就是 ± 0.01 类似, 1-sigma 是 60%多, 而且基本符合均匀分布, 除了中间均值比较多一点点, 3-sigma 是 9544, 3-sigma 是9974, 即几乎 ± 0.02 以内就得了. 而本题用的 labels 大约是0~20都有的, 可以加这个噪声.

代码片段 A.2
%matplotlib inline
import torch
# display can display image, and latex math, just add this
from IPython import display
from matplotlib import pyplot as plt
import numpy as np
import random

print(torch.__version__)

num_inputs = 2
num_examples = 10
true_w = torch.tensor([[2], [-3.4]])
true_b = 4.2
features = torch.randn(num_examples, num_inputs,
                      dtype=torch.float32)
# labels = true_w[0] * features[:, 0] + true_w[1] * features[:, 1] + true_b
labels = torch.mm(features, true_w) + true_b
noise = torch.tensor(np.random.normal(0, 0.01, size=labels.size()),
                       dtype=torch.float32)
labels += noise
true_w = torch.squeeze(true_w)
labels = torch.squeeze(labels)
print('features:', features)
print('labels:', labels)
print('noise:', noise)
print('weight and bias:', true_w, true_b)
print(labels.size(), type(labels.size()), labels.shape, type(labels.shape))

def set_figsize(figsize=(3.5, 2.5)):
    plt.rcParams['figure.figsize'] = figsize

set_figsize()
plt.scatter(features[:, 0].numpy(), labels.numpy(), 1)
plt.scatter(features[:, 1].numpy(), labels.numpy(), 1);

讲解:
1.display 不管他, 反正要用.
2.以 Tensor 角度思考, 特征是一个量, 即特征量, 只不过有多个维度, 如上面的两维, 所以他相加是有权重的, 参数 w 也是有两维度, 而 torch.randn(100, 2) 正是理解为有100个数据, 然后多一个最后的特征维, 是2.
3.Tensor 的维度切片调用和 np 一样, 都是 a[:, :, 0]这样的.
4.代码改了点, 强行使用了矩阵运算, 或者说是把构造用的 true_w 也必须和 features 整体操作, 原来是维度像 3 一样维度拆开的, 而不拆开一是可是用我上面的, 1002 mm 21, 全是矩阵, 或者用向量对应位置乘法, 再特征维度求和. 不过不用较真.
5.torch.squeeze(input, dim=None, out=None) → Tensor

所有的 1 维度都去掉并且: The returned tensor shares the storage with the input tensor, so changing the contents of one will change the contents of the other. 所以就是原来的等于原来的去用, 别 y = x, 然后改了 y, 又去用 x, 就说不清了. 多起个名字就好.
6.torch.tensor(data, dtype=None, device=None, requires_grad=False, pin_memory=False) → Tensor

注意这个方法会完全拷贝送进去的 data, 以及想要有 gradient, 需要人为指定, 以及注意 GPU 的指定. 不知道为什么强调那么多 copy, detach, leaf 等, 不懂.
7.np.random.normal(0, 0.01, size=labels.size()). 目前看来 labels 是 Tensor, 而 size() 是 <class ‘torch.Size’>, 可以默认转换为 numpy.shape. 记住就好了.
8.plt.rcParams[‘figure.figsize’], 可以设置大小, 变为 100 * 100 的超大的, 可以看清楚, 但是不知道对应的单位是什么, 不过意义也不大.

6. 读取数据集

涉及到分 batch, 以及随机读取, 还有一次 epoch 读完后干什么

代码片段 A.3
def data_iter(batch_size, features, labels):
    num_examples = len(features)
    indices = list(range(num_examples))
    random.shuffle(indices)  # 样本的读取顺序是随机的
    for i in range(0, num_examples, batch_size):
        j = torch.LongTensor(indices[i: min(i + batch_size, num_examples)]) # 最后一次可能不足一个batch
        print('what?', j)
#         yield features[j], labels[j]
#         yield features[j, :], labels[j]
        yield  features.index_select(0, j), labels.index_select(0, j)

batch_size = 10
steps_per_epoch = 0
for X, y in data_iter(batch_size, features, labels):
#     print(X, '\n', y)
    steps_per_epoch += 1
print('batch num:', steps_per_epoch)

解析:
1.data_iter 接口就这么固定了, 最简化的 feature 结构为 [num, X, X…], labels 为 [num, Y, Y…], 然后就可以避免占用内存过大, 使用 yield 机制来绕过. 缺点是速度慢, 实际还是得开 feeder 多线程. 到时候再说.
2.features.index_select(维度, [2, 4, 5…]) 和 切片直接取区别不大, 不知道为什么. 关键是他是拷贝出来了一份, 跟原有的 Tensor 无关, 而且需要 index 是 LongTensor.
3.torch.LongTensor, 就是整数 Tensor 的意思, 记住 torch.LongTensor 这个转换.
Tensor.long() 也是可以的.

7. 定义model, loss, opt

关键是 pytorch 的 Tensor 是真正的变量, 在 def 之内的, 之后求到最后, 再返回来求梯度时, 会提前被销毁, 只是算了一遍而已 (当然, 是以目前我接触的 Pytorch 而言, 下一节课会怎样特别说明如 def 临时变量也可记录, 则与 Tensorflow 先刻好板子就有些像了, 即不管变量在哪里, 变量只负责刻板子, 得到一个板子即是静态图, 那么动态图又是什么呢?)

代码片段 A.4
w = torch.tensor(np.random.normal(0, 0.01, (num_inputs, 1)), dtype=torch.float32)
b = torch.zeros(1, dtype=torch.float32)
def test(x):
    bb = torch.ones(1) *
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值