神经网络-教学(第一课)

一、神经网络第一课

  • 神经网络分类
  • 激励函数
  • 过拟合
  • 网络搭建
  • 数据集搭建
  • 开始训练
  • 调整参数

注:没有我讲 是很难看懂滴

二、神经网络分类

从代码的角度来讲,主要分为2类,线性网络和卷积网络。

2.1 线性网络

线性网络大致如下图,对一维数据进行操作

1567007772473

  • 神经元:激励函数,一般为relu、sigmod等,也可以没有
  • 黑色的线:$y = wx + b$,在代码中b(bias)默认有,可以通过设置取消

建立线性网络格式如下,这种建立只是为了把网络搭建起来,具体的激励还得另外写

1
nn.Linear(inputChannel, outputChannel,bias = True)

2.2 卷积网络

卷积网络大致如下,是对二维数据进行操作,如图片

1567008272958

  • 神经元:激励函数
  • 黑色的线:如上线性网络一样
  • 建立卷积网络代码如下:
1
nn.Conv2d(in_channels, out_channels, kernel_size=kernel_size, stride=stride, padding=padding,bias=bias)

三、激励函数

如果没有激励函数的话,那么层和层之间的传递关系式为:$y = wx + b$,可以看到这个为一次函数。一次函数的缺点很明显,值域无穷,反正在一些对值域有要求的情况下就会不好。所以后面提出了sigmod,tanh等激励函数。

这些常用的激励函数见下链接:点我

四、过拟合

简而言之,学习能力太强,把数据全部记住了,以后除了训练数据能输出正确结果,其他的都不认。

造成原因:数据集太少(主要原因),学习迭代次数过多。解决方法,使用dropout函数,在每次学习的时候使一些神经元的数据失效,一般放在最后一层网络层来用。

五、网络搭建

网络搭建是整个神经网络代码中最简单的部分,下面用数据对一次函数拟合,先给出拟合完成的图片。如图所示,红色为拟合结果,蓝色为数据。

1567008954618

注:最下面那个(0,0,)点是绘图程序写的不严谨出现的,和网络输出无关

设计思路非常简单,使用简单的一个神经元就好

1
2
3
4
5
6
7
8
9
class net(nn.Module):
def __init__(self):
super(net, self).__init__()
self.fc1 = nn.Linear(1,1)

def forward(self, x):
out = self.fc1(x)

return out

对这个网络建立的细节进行一些讲解和注意事项。此时只学习$w,b$

六、数据集搭建

这是整个神经网络中最繁琐的地方,大部分时候需要自己搜集,如果是图片,动辄就是几万张。但是这里拟合的话,数据就可以模拟生成。

1
2
3
4
5
6
7
8
9
10
11
12
def generateData(k, b):
dataSet = torch.tensor(torch.zeros([200,2]))
for i in range(40):
for n in range(5):
rand_x = torch.randn(1)[0]
rand_y = torch.randn(1)[0]
dataSet[i*5 + n,:] = torch.tensor([i + rand_x, rand_y*10 + k * i + b])

# print(dataSet)
# plt.scatter(dataSet[:,0],dataSet[:,1])
# plt.show()
return dataSet

这里使用在确定的一次函数,通过正太分布的的随机值,参数随机坐标。结果如图所示:

1567009359267

将生成的数据打印出来看

七、开始训练

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
model = net()
# 在这里打印网络参数,通过随机数据测试网络是否可以用torch.randn([10,1]),介绍网络数据输入方式

dataSet = generateData(5,20)
# 把数据格式打印出来
# print(dataSet)

optimizer = torch.optim.SGD(model.parameters(), lr= lr) # 采用梯度下降算法
loss_func = nn.MSELoss() # 损失函数,如何计算损失?

for eoach in range(1000): # 循环迭代1000次,(当然用不了这么多次)
outlist = torch.tensor(torch.zeros([200,2])) # 用于结果绘图,可以不看
loss_avg = 0
for index, (odata, olabel) in enumerate(dataSet):
# 这里要对网络上一些使用Var** 作为设计梯度的错误说明
x = torch.tensor([odata], requires_grad=True).float()
label = torch.tensor([olabel]).float()

out = model(x)

loss = loss_func(out, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()

loss_avg = loss_avg + loss.data.numpy() # 记录损失
outlist[odata.data.numpy()] = torch.tensor([odata.data, out.data])

print(loss_avg / 1000) # 打印损失

# 绘制图像
plt.clf()
plt.axis([-1,50,-10,250])
plt.scatter(dataSet[:,0],dataSet[:,1])
plt.scatter(outlist[:,0],outlist[:,1],c="r")
plt.pause(0.01)

八、调试

如果参数不对或者不合适的话,就会出现nan、或者拟合的一次函数的偏置b貌似为0,此时需要进行调试,查看那里出现了问题,打印网络节点参数(一个网络可以这么调试,几万个我就不知道了)

1
2
for name, param in model.named_parameters():
print(name,param)

通过参数可以看到,偏置b在变动,只不过变动的非常缓慢,没有w变动的快,此时可以通过调整b的学习速率

九、调整学习速率

1
2
3
4
5
6
7
optimizer = torch.optim.SGD([
# encoder-weights
{'params': model.fc1.weight, 'lr': lr},
# encoder-bias
{'params': model.fc1.bias, 'lr': lr * 100},

], lr=lr)

这样就可以了,但是这样如果面对很多层网络,手写肯定不是办法,下面采用一个函数来解决

1
2
3
4
5
6
7
8
9
10
def setparamsLr(model,lr):
params = []
params_dict = dict(model.named_parameters())

for key,value in params_dict.items():
if "weight" in key:
params.append({'params': value, 'lr': lr})
elif "bias" in key:
params.append({'params': value,'lr': lr*100})
return params

十、数据集操作(补充,不重要)

如果想要对数据集进行一些特殊的操作,比如一次取出多组数据,打乱数据集呢。这里就需要使用数据集对应的库。先给个可以单独运行的例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from torch.utils import data
from torch.utils.data import TensorDataset
import torch

a = [1,2,3,4] # Data
b = [6,7,8,9] # Lable

c = TensorDataset(torch.tensor(a),torch.tensor(b))

d = data.DataLoader(dataset=c,batch_size=2,shuffle=True)

for index,(D,L) in enumerate(d):
print("index:%d"%index)
print(D)
print(L)

细致修改有些复杂,后面再说

十一、loss函数自定义

如果我不是输出预测值,而是要求w,b的具体值,改怎么做。

此时就是多项式拟合,拟合系数,可以参考百度教程,此时就需要自定义loss,因为网络输出的结果经过一定计算才可以得到具体损失。

-------------本文结束感谢您的阅读-------------
0%