Pytorch动态
Tensorflow 就是最典型的静态计算模块. 用 Tensorflow 是先搭建好这样一个计算系统, 一旦搭建好了, 就不能改动了
(也有例外, 比如dynamic_rnn(), 但是总体来说他还是运用了一个静态思维), 所有的计算都会在这种图中流动,
有时候 RNN 的 time step 不会一样, 或者在 training 和 testing 的时候, batch_size 和 time_step 也不一样, 这时就需要动态计算
动态RNN
######################## 前面代码都一样, 下面开始不同 #########################
################ 那节内容的代码结构 (静态 time step) ##########
for step in range(60):
start, end = step * np.pi, (step+1)*np.pi # time steps 都是一样长的
# use sin predicts cos
steps = np.linspace(start, end, 10, dtype=np.float32)
...
################ 这节内容修改代码 (动态 time step) #########
step = 0
for i in range(60):
dynamic_steps = np.random.randint(1, 4) # 随机 time step 长度
start, end = step * np.pi, (step + dynamic_steps) * np.pi # different time steps length
step += dynamic_steps
# use sin predicts cos
steps = np.linspace(start, end, 10 * dynamic_steps, dtype=np.float32)
####################### 这下面又一样了 ###########################
print(len(steps)) # print how many time step feed to RNN
x_np = np.sin(steps) # float32 for converting torch FloatTensor
y_np = np.cos(steps)
...
"""
输出的动态time step 长
30
30
10
30
20
30
"""GPU加速运算
在 GPU 训练可以大幅提升运算速度. 而且 Torch 也有一套很好的 GPU 运算体系.
但是要强调的是: *电脑里有合适的 GPU 显卡(NVIDIA), 且支持 CUDA 模块.
修改:数据+CNN模块+训练数据+计算图纸
用GPU训练CNN
将数据的形式变成 GPU 能读的形式, 将 CNN 也变成 GPU 能读的形式. 做法就是在后面加上 .cuda()
test_data = torchvision.datasets.MNIST(root='./mnist/', train=False)
# !!!!!!!! 修改 test data 形式 !!!!!!!!! #
test_x = torch.unsqueeze(test_data.test_data, dim=1).type(torch.FloatTensor)[:2000].cuda()/255. # Tensor on GPU
test_y = test_data.test_labels[:2000].cuda()CNN 参数也变成 GPU 兼容形式.
class CNN(nn.Module):
...
cnn = CNN()
# !!!!!!!! 转换 cnn 去 CUDA !!!!!!!!! #
cnn.cuda() # Moves all model parameters and buffers to the GPU.在 train 的时候, 将每次的training data 变成 GPU 形式. + .cuda()
for epoch ..:
for step, ...:
# !!!!!!!! 这里有修改 !!!!!!!!! #
b_x = x.cuda() # Tensor on GPU
b_y = y.cuda() # Tensor on GPU
...
if step % 50 == 0:
test_output = cnn(test_x)
# !!!!!!!! 这里有修改 !!!!!!!!! #
pred_y = torch.max(test_output, 1)[1].cuda().data.squeeze() # 将操作放去 GPU
accuracy = torch.sum(pred_y == test_y) / test_y.size(0)
...
test_output = cnn(test_x[:10])
# !!!!!!!! 这里有修改 !!!!!!!!! #
pred_y = torch.max(test_output, 1)[1].cuda().data.squeeze() # 将操作放去 GPU
...
print(test_y[:10], 'real number')如果还有要在CPU 上进行的, 比如 plt 的可视化, 需要将这些计算或者数据转移至 CPU.
cpu_data = gpu_data.cpu()过拟合 (Overfitting)
自负的坏处, 大家也知道, 就是在自己的小圈子里表现非凡, 不过在现实的大圈子里却往往处处碰壁
回归分类的过拟合


机器学习模型的自负表现:
这里是一些数据. 如果要你画一条线来描述这些数据, 大多数人都会这么画. 这时蓝线与数据的总误差可能是10.
可是有时候, 机器过于纠结这误差值, 他想把误差减到更小, 来完成他对这一批数据的学习使命. 所以, 他学到的可能几乎经过了每一个数据点, 这样, 误差值会更小 .
但当拿这个模型运用在现实中的时候, 自负就体现出来.
这时, 之前误差大的蓝线误差基本保持不变 .误差小的 红线误差值突然飙高 , 自负的红线不能成功的表达除了训练数据以外的其他数据.
解决方法
方法一: 增加数据量, 大部分过拟合产生的原因是因为数据量太少了. 如果我们有成千上万的数据, 红线也会慢慢被拉直, 变得没那么扭曲 . 方法二:运用正规化.

我们简化机器学习的关键公式为 y=Wx . W为机器需要学习到的各种参数. 在过拟合中, W 的值往往变化得特别大或特别小.
为了不让W变化太大, 我们在计算误差上做些手脚. 原始的 cost 误差计算:cost = 预测值-真实值的平方.
如果 W 变得太大, 就让 cost 也跟着变大, 变成一种惩罚机制.
这里 abs 是绝对值. 这一种形式的 正规化, 叫做 l1 正规化. L2 正规化和 l1 类似, 只是绝对值换成了平方.
其他的l3, l4 也都是换成了立方和4次方等等. 形式类似. 用这些方法就能保证让学出来的线条不会过于扭曲.

还有一种专门用在神经网络的正规化的方法, 叫作 dropout.
在训练的时候, 我们随机忽略掉一些神经元和神经联结 , 是这个神经网络变得”不完整”. 用一个不完整的神经网络训练一次.到第二次再随机忽略另一些, 变成另一个不完整的神经网络.
有了这些随机 drop 掉的规则, 我们可以想象其实每次训练的时候, 我们都让每一次预测结果都不会依赖于其中某部分特定的神经元. 像l1, l2正规化一样, 过度依赖的 W , 也就是训练参数的数值会很大, l1, l2会惩罚这些大的 参数. Dropout 的做法是从根本上让神经网络没机会过度依赖.
Dropout 缓解过拟合
做点数据
做10个数据点

import torch
import matplotlib.pyplot as plt
torch.manual_seed(1) # reproducible
N_SAMPLES = 20
N_HIDDEN = 300
# training data
x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)
y = x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))
# test data
test_x = torch.unsqueeze(torch.linspace(-1, 1, N_SAMPLES), 1)
test_y = test_x + 0.3*torch.normal(torch.zeros(N_SAMPLES, 1), torch.ones(N_SAMPLES, 1))
# show data
plt.scatter(x.data.numpy(), y.data.numpy(), c='magenta', s=50, alpha=0.5, label='train')
plt.scatter(test_x.data.numpy(), test_y.data.numpy(), c='cyan', s=50, alpha=0.5, label='test')
plt.legend(loc='upper left')
plt.ylim((-2.5, 2.5))
plt.show()搭建神经网络
搭建两个神经网络, 一个没有 dropout, 一个有 dropout.
没有 dropout 的容易出现 过拟合, 那我们就命名为 net_overfitting, 另一个就是 net_dropped.
torch.nn.Dropout(0.5) 这里的 0.5 指的是随机有 50% 的神经元会被关闭/丢弃.
net_overfitting = torch.nn.Sequential(
torch.nn.Linear(1, N_HIDDEN),
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDEN, N_HIDDEN),
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDEN, 1),
)
net_dropped = torch.nn.Sequential(
torch.nn.Linear(1, N_HIDDEN),
torch.nn.Dropout(0.5), # drop 50% of the neuron
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDEN, N_HIDDEN),
torch.nn.Dropout(0.5), # drop 50% of the neuron
torch.nn.ReLU(),
torch.nn.Linear(N_HIDDEN, 1),
)训练
两个神经网络分开训练,训练环境一样
optimizer_ofit = torch.optim.Adam(net_overfitting.parameters(), lr=0.01)
optimizer_drop = torch.optim.Adam(net_dropped.parameters(), lr=0.01)
loss_func = torch.nn.MSELoss()
for t in range(500):
pred_ofit = net_overfitting(x)
pred_drop = net_dropped(x)
loss_ofit = loss_func(pred_ofit, y)
loss_drop = loss_func(pred_drop, y)
optimizer_ofit.zero_grad()
optimizer_drop.zero_grad()
loss_ofit.backward()
loss_drop.backward()
optimizer_ofit.step()
optimizer_drop.step()对比测试结果
在这个 for 循环里, 我们加上画测试图的部分.
注意在测试时, 要将网络改成 eval() 形式, 特别是 net_dropped, net_overfitting画好图再改回 train() 模式.

optimizer_ofit.step()
optimizer_drop.step()
# 接着上面来
if t % 10 == 0: # 每 10 步画一次图
# 将神经网络转换成测试形式, 画好图之后改回 训练形式
net_overfitting.eval()
net_dropped.eval() # 因为 drop 网络在 train 的时候和 test 的时候参数不一样.
...
test_pred_ofit = net_overfitting(test_x)
test_pred_drop = net_dropped(test_x)
...
# 将两个网络改回 训练形式
net_overfitting.train()
net_dropped.train()
















