神经网络就是一堆矩阵乘来乘去,而矩阵里是什么数字全靠算法计算,我们只需要提供一堆输入数据和输出, 那么依靠反向传播算法,神经网络就能自动计算出最合适的参数,从而实现训练。
这是Python的深度学习框架,我们用它实现神经网络,
cpu版本直接执行pip install torch
,gpu版本请去官网获取安装命令
假如有个函数,输入30个1~100的数字,返回他们的和,如何用神经网络实现这个函数呢?多神经的案例啊
定义输入层大小,输出层大小,中间层大小,中间层数量,创建神经网络
import torch
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = torch.nn.Linear(30, 60)
self.fc2 = torch.nn.Linear(60, 60)
self.fc3 = torch.nn.Linear(60, 1)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = torch.relu(self.fc3(x))
return x
该类就是个神经网络,输入层大小为30,输出层大小为1,中间层大小为60,中间层数量为2
内部其实就是传入nx30的矩阵,乘以30x60的矩阵,再乘以60x60的矩阵,最后乘以60x1的矩阵,最后返回nx1的矩阵
而矩阵内部是什么值并不是人能猜的,所以只能训练,给他输入和输出,让他通过反向传播算法,自己计算出最合适的参数
一个数学线性函数与另一个线性函数组合能得到一个新的线性函数。同样,没有激活函数的多个线性层实际上等价于单个线性层。
所以激活函数的作用就是增加神经网络的非线性,比如torch.relu(),用于使神经网络能够学习和表示复杂的非线性关系
将数据按比例缩放到特定范围(如[0,1]或[-1,1])的过程
有些激活函数遇到很大的数值时,输出会接近0,导致无法训练,所以需要归一化。
就好比在山坡上开车,归一化就是将坡度降低,让车能正常行驶
# 创建神经网络实例
net = Net()
# 输入,30个0~100的随机数,并归一化(全部除100)
inputs = torch.FloatTensor(np.random.randint(0, 101, 30) / 100.0)
# 神经网络输出
outputs = net(inputs)
# 目标值,30个(0~100)/100的和
targets = torch.sum(inputs)
print(inputs)
print(outputs)
print(targets)
输入
[0.4200, 0.6600, 0.0300, 0.2600, ...]
[0.2]
[6]
计算输出与目标值的误差,然后清除梯度,并反向传播误差,最后更新参数
# 定义损失函数和优化器
criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
# 计算损失
loss = criterion(outputs, targets)
# 反向传播和优化
optimizer.zero_grad()
loss.backward()
optimizer.step()
def train_network():
net = Net()
criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
# 训练循环
for epoch in range(3000):
# 32行,代表32个批次,每行30个数字,并归一化
inputs = torch.FloatTensor(np.random.randint(0, 101, (32, 30)) / 100)
outputs = net(inputs)
# 目标值,每行求和,返回32行1列的矩阵
targets = torch.sum(inputs, dim=1, keepdim=True)
loss = criterion(outputs, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每100个epoch打印一次损失
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch+1}/3000], Loss: {loss.item():.4f}')
return net
print("开始训练网络...")
trained_net = train_network()
print("开始测试!")
trained_net.eval() # 设置为评估模式
test_inputs_raw = np.random.randint(0, 101, (10, 30)) / 100
test_inputs = torch.FloatTensor(test_inputs_raw)
with torch.no_grad(): # 测试时不需要计算梯度
test_outputs = trained_net(test_inputs)
test_targets = torch.sum(torch.FloatTensor(test_inputs_raw), dim=1, keepdim=True)
for i in range(len(test_outputs)):
predicted = test_outputs[i].item()
target = test_targets[i].item()
error = abs(predicted - target)
# 修改显示输入数据的前5个元素
input_str = "[" + ", ".join(map(str, test_inputs_raw[i][:5])) + ", ...]"
print(f"{i+1:<4} {input_str:<20} {predicted:<12.2f} {target:<12.2f} {error:<10.2f}")
输出
D:\Python310\python.exe D:\PythonProjects\Learn\temp.py
开始训练网络...
Epoch [100/3000], Loss: 0.3356
Epoch [200/3000], Loss: 0.1059
...
Epoch [1400/3000], Loss: 0.0011
Epoch [1500/3000], Loss: 0.0005
...
Epoch [3000/3000], Loss: 0.0000
1 [0.66, 0.76, 0.95, 0.53, 0.81, ...] 16.09 16.09 0.00
2 [0.93, 0.15, 0.13, 0.01, 0.87, ...] 14.62 14.62 0.00
3 [0.51, 1.0, 0.87, 0.28, 0.64, ...] 14.10 14.10 0.00
4 [0.6, 0.07, 0.74, 0.41, 0.04, ...] 17.24 17.24 0.00
5 [0.95, 0.85, 0.3, 0.44, 0.42, ...] 15.30 15.30 0.00
...
可以看到测试结果和目标值误差都为0,说明训练成功
全部代码
import torch
import numpy as np
class Net(torch.nn.Module):
def __init__(self):
super(Net, self).__init__()
self.fc1 = torch.nn.Linear(30, 60)
self.fc2 = torch.nn.Linear(60, 60)
self.fc3 = torch.nn.Linear(60, 1)
def forward(self, x):
x = torch.relu(self.fc1(x))
x = torch.relu(self.fc2(x))
x = torch.relu(self.fc3(x))
return x
def train_network():
net = Net()
criterion = torch.nn.MSELoss()
optimizer = torch.optim.Adam(net.parameters(), lr=0.001)
# 训练循环
for epoch in range(3000):
# 32行,每行30个数字,代表32个批次,并归一化
inputs = torch.FloatTensor(np.random.randint(0, 101, (32, 30)) / 100)
outputs = net(inputs)
# 目标值,每行求和,返回32行1列的矩阵
targets = torch.sum(inputs, dim=1, keepdim=True)
loss = criterion(outputs, targets)
optimizer.zero_grad()
loss.backward()
optimizer.step()
# 每100个epoch打印一次损失
if (epoch + 1) % 100 == 0:
print(f'Epoch [{epoch + 1}/3000], Loss: {loss.item():.4f}')
return net
def main():
# 训练网络
print("开始训练网络...")
trained_net = train_network()
print("开始测试!")
trained_net.eval() # 设置为评估模式
test_inputs_raw = np.random.randint(0, 101, (10, 30)) / 100
test_inputs = torch.FloatTensor(test_inputs_raw)
with torch.no_grad(): # 测试时不需要计算梯度
test_outputs = trained_net(test_inputs)
test_targets = torch.sum(torch.FloatTensor(test_inputs_raw), dim=1, keepdim=True)
for i in range(len(test_outputs)):
predicted = test_outputs[i].item()
target = test_targets[i].item()
error = abs(predicted - target)
# 修改显示输入数据的前5个元素
input_str = "[" + ", ".join(map(str, test_inputs_raw[i][:5])) + ", ...]"
print(f"{i+1:<4} {input_str:<20} {predicted:<12.2f} {target:<12.2f} {error:<10.2f}")
if __name__ == "__main__":
main()