2021年人工神经网络第一次作业:参考答案-1
简 介: 本文给出了 2021年人工神经网络第一次作业要求 中,由同学提交的作业示例。
关键词
: 人工神经网络,感知机,BP,数据压缩
0.1 背景介绍
针对于 2021年人工神经网络第一次作业要求 中,提交作业中具有典型的代表。
- 作业作者:樊懿轩,2021310712
§01 感知机
本题相关代码见q1.py
,网络结构如下所示,激活函数为符号函数。
def train(train_data, mode):
def sgn(x, mode):
if x >= 0:
return 1
else:
return mode
weight = [0., 0., 0.]
bias = 0.
learning_rate = 100
epoch = 30
for num in range(epoch):
for x, y in train_data:
predict = sgn(weight[0] * x[0] + weight[1] * x[1] + weight[2] * x[2] + bias, mode)
print("train data: x: (%d, %d, %d) y: %d ==> predict: %f" % (x[0], x[1], x[2], y, predict))
if y != predict:
weight[0] = weight[0] + learning_rate * (y - predict) * x[0]
weight[1] = weight[1] + learning_rate * (y - predict) * x[1]
weight[2] = weight[2] + learning_rate * (y - predict) * x[2]
bias = bias + learning_rate * (y - predict)
print("epoch: %d updated weight: (%f, %f, %f) bias: %f" % (num + 1, weight[0], weight[1], weight[2], bias))
return weight, bias
train_data1 = [([1, 1, 1], 1), ([1, 1, 0], 0), ([1, 0, 1], 0), ([0, 1, 1], 0)]
train_data2 = [([1, 1, 1], 1), ([1, 1, -1], -1), ([1, -1, 1], -1), ([-1, 1, 1], -1)]
print('------Mode1------')
train(train_data1, mode=0)
print('------Mode2------')
train(train_data2, mode=-1)
▲ 图1.1 感知机的结构
算法轮流将训练数据输入网络并计算输出,当输出和期望输出不符时以学习速率调整参数直至收敛。在训练过程中,将按顺序使用完四组训练样本称为完成一轮训练;当一轮训练中均不出现需要调整参数的情况时,认为算法收敛,下表记录学习速率和数据表达方式对收敛速率的影响。可见适当调整学习速率有助于加快收敛,双极性的数据表达方式在本题实现的模型中能够更快收敛。
▲ 图1.2 不同数据结构以及学习速率对应的收敛速度
§02 模式分类
2.1 单层BP网络
本题相关代码见q2_1.py
,网络结构如下所示,激活函数为Tanh
函数。
import torch
from torch import nn
from torch.utils.data import DataLoader, Dataset
HIDDEN_UNIT = 10
NOISE = True
class ClsDataset(Dataset):
def __init__(self):
self.dataset = [([0.75, 1], [1, -1, -1]), ([1, 0.5], [1, -1, -1]), ([0.5, 0.25], [1, -1, -1]), ([0.5, 0.75], [-1, 1, -1]),
([1, 0.75], [-1, 1, -1]), ([0.75, 0.25], [-1, 1, -1]), ([0.25, 0.25], [-1, -1, 1]), ([0.75, 0.5], [-1, -1, 1]),
([0.75, 0.75], [-1, -1, 1])]
def __len__(self):
return len(self.dataset)
def __getitem__(self, index):
if NOISE:
return torch.Tensor(self.dataset[index][0]) + torch.rand(2) / 2 - 0.25, torch.Tensor(self.dataset[index][1])
return torch.Tensor(self.dataset[index][0]), torch.Tensor(self.dataset[index][1])
class cls(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(in_features=2, out_features=HIDDEN_UNIT), nn.Tanh(),
nn.Linear(in_features=HIDDEN_UNIT, out_features=3), nn.Tanh())
def forward(self, *x):
x = self.model(x[0])
return x
clsdataset = ClsDataset()
model = cls()
data_loader = DataLoader(dataset=clsdataset, batch_size=9)
loss_func = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.03, momentum=0.9)
for epoch in range(5000):
model.train()
for cnt, data in enumerate(data_loader):
x_data, y = data
pred = model(x_data)
acc = (pred.max(dim=1)[1] == y.max(dim=1)[1]).sum() / y.shape[0]
loss = loss_func(pred, y)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print('epoch: %2d loss: %4f acc: %4f' % (epoch + 1, loss, acc))
▲ 图2.1.1 BP网络结构
每次训练使用全部九个样本,先前向传播计算结果,计算MSE 损失再反向传播更新参数直至收敛(所有样本均预测正确)。实验结果显示最少需要三个隐层节点才可以解决该分类问题。经验和实验结果表明,隐层数量在一定范围内增多能够提高网络表达能力并加快收敛。受噪声影响时,网络难以完全收敛,这是由于噪声过于明显。
2.2 RBF网络
本题相关代码见q2_2.py
,网络的参数和仿真结果可在程序运行时在终端的输出信息中查看,所有样本都可以被正确分类。
import numpy as np
x_data = np.array([[0.75, 1], [1, 0.5], [0.5, 0.25], [0.5, 0.75], [1, 0.75], [0.75, 0.25], [0.25, 0.25], [0.75, 0.5], [0.75, 0.75]])
y_data = np.array([[1, -1, -1], [1, -1, -1], [1, -1, -1], [-1, 1, -1], [-1, 1, -1], [-1, 1, -1], [-1, -1, 1], [-1, -1, 1], [-1, -1, 1]])
def rbf_hide_out(x, H, sigma):
Hx = H - x
Hxx = [np.exp(-np.dot(e, e) / (sigma**2)) for e in Hx]
return Hxx
print('--------Part 1--------')
Hdim = np.array([rbf_hide_out(x, x_data, 0.5) for x in x_data]).T
w = np.dot(y_data.T, np.dot(np.linalg.inv(np.eye(9) * 0.001 + np.dot(Hdim.T, Hdim)), Hdim.T))
print('------parameters------')
print(w)
print('----------------------')
yy = np.dot(w, Hdim)
yy1 = np.array([[1 if e > 0 else -1 for e in l] for l in yy])
print(yy1)
err = [1 if any(x1 != x2) else 0 for x1, x2 in zip(yy1.T, y_data)]
print(err)
print('----------------------')
print('--------Part 2--------')
RBF_HIDE_NODE = 4
for chance in range(500):
node = x_data
np.random.shuffle(node)
node = node[:RBF_HIDE_NODE]
Hdim = np.array([rbf_hide_out(x, node, 0.5) for x in x_data]).T
w = np.dot(y_data.T, np.dot(np.linalg.inv(np.eye(9) * 0.001 + np.dot(Hdim.T, Hdim)), Hdim.T))
yy = np.dot(w, Hdim)
yy1 = np.array([[1 if e > 0 else -1 for e in l] for l in yy])
err = [1 if any(x1 != x2) else 0 for x1, x2 in zip(yy1.T, y_data)]
if sum(err) == 0:
print('success')
当使用广义RBF
网络时,若要求所有样本均可被正确分类,使用部分训练样本作为隐层节点,隐层最少需要4
个节点。
§03 函数逼近
3.1 单隐层BF网络
本题相关代码见q3_1.py
,网络使用100
× 100
均匀采集的样本作为训练集,101
× 101
均匀采集的样本作为验证集,保证除四角外没有和训练集重合的点。训练时以10
作为隐层单元数,以1000
作为批大小,下表显示了不同激活函数对收敛速度(考察验证集平均损失,使用均方误差)的影响。
▲ 图3.1 不同隐层传递函数对应网络收敛效果
结果显示了Tanh
激活函数在本特定任务上的优势。
import torch
from torch import nn
from torch.utils.data import DataLoader, Dataset
HIDDEN_UNIT = 10
class ApproachDataset(Dataset):
def __init__(self, train):
if train:
self.step = 100
else:
self.step = 101
self.x = torch.linspace(-4, 4, steps=self.step)
def __len__(self):
return len(self.x) * len(self.x)
def __getitem__(self, index):
xx = self.x[int(index / self.step)]
yy = self.x[index % self.step]
return xx, yy, torch.Tensor(
[3 * (1 - xx)**2 * torch.exp(-xx**2 - (yy + 1)**2) - 10 * (xx / 5 - xx**3 - yy**5) * torch.exp(-xx**2 - yy**2) - torch.exp(-(xx + 1)**2 - yy**2) / 3])
class Approach(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(in_features=2, out_features=HIDDEN_UNIT), nn.ReLU(), nn.Linear(in_features=HIDDEN_UNIT, out_features=1))
def forward(self, *x):
x = self.model(x[0])
return x
train_dataset = ApproachDataset(train=True)
eval_dataset = ApproachDataset(train=False)
train_loader = DataLoader(dataset=train_dataset, batch_size=1000, shuffle=True)
eval_loader = DataLoader(dataset=eval_dataset, batch_size=101 * 101)
model = Approach()
loss_func = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.03, momentum=0.9)
for epoch in range(100):
model.train()
for cnt, data in enumerate(train_loader):
x1, x2, label = data
pred = model(torch.stack((x1, x2), 1))
loss = loss_func(pred, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 1 == 0:
model.eval()
with torch.no_grad():
for cnt, data in enumerate(eval_loader):
x1, x2, label = data
pred = model(torch.stack((x1, x2), 1))
eval_loss = loss_func(pred, label)
print('epoch: %2d train_loss: %4f eval_loss: %4f' % (epoch + 1, loss, eval_loss))
3.2 RBF网络
本题相关代码见q3_2.py
,网络使用100
× 100
均匀采集的样本作为训练集,训练时以10
作为隐层单元数,下表显示了不同尺度参数对逼近效果的影响。
不同尺度参数对于逼近效果的影响:
▲ 图3.2.1 不同尺度参数对于逼近效果的影响
结果显示合适的尺度参数能够获得更好的逼近效果。
import numpy as np
x_lin = list(np.linspace(-4, 4, 100))
x_data = []
for x_1 in range(100):
for x_2 in range(100):
x_data.append([x_lin[x_1], x_lin[x_2]])
x_data = np.array(x_data)
y_data = 3 * (1 - x_data[:, 0])**2 * np.exp(-x_data[:, 0]**2 - (x_data[:, 1] + 1)**2) - 10 * (
x_data[:, 0] / 5 - x_data[:, 0]**3 - x_data[:, 1]**5) * np.exp(-x_data[:, 0]**2 - x_data[:, 1]**2) - np.exp(-(x_data[:, 0] + 1)**2 - x_data[:, 1]**2) / 3
def rbf_hide_out(x, H, sigma):
Hx = H - x
Hxx = [np.exp(-np.dot(e, e) / (sigma**2)) for e in Hx]
return Hxx
RBF_HIDE_NODE = 10
node = x_data
np.random.shuffle(node)
node = node[:RBF_HIDE_NODE]
Hdim = np.array([rbf_hide_out(x, node, 10) for x in x_data]).T
w = np.dot(y_data.T, np.dot(np.linalg.inv(np.eye(10000) * 0.001 + np.dot(Hdim.T, Hdim)), Hdim.T))
print('------parameters------')
print(w)
print('----------------------')
yy = np.dot(w, Hdim)
print(yy)
err = ((y_data - yy)**2).mean()
print(err)
§04 数据压缩
本题相关代码见q4.py
。理论和实验结果都可以指出,在其它条件一致的情况下隐层节点增多有助于降低恢复数据误差。使用学习率为1.0
的随机梯度下降优化器训练5000
轮后,隐层节点数和恢复数据误差(数据点平均正确率)的关系如下表所示。
▲ 图4.1 隐层节点数域恢复数据误差
使用15
个隐层节点时恢复的结果见ascii_output.txt
。
import torch
from torch import nn
from torch.utils.data import DataLoader, Dataset
HIDDEN_UNIT = 15
class alphabetDataset(Dataset):
def __init__(self):
self.dataset = []
with open('ascii8x16.txt', 'r', encoding="utf-8") as file:
for alpha_cnt, alpha_data in enumerate(file):
self.dataset.append([])
for num in alpha_data[:-1]:
self.dataset[alpha_cnt].append(int(num))
def __len__(self):
return len(self.dataset)
def __getitem__(self, index):
return torch.Tensor(self.dataset[index])
class alphabet(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(in_features=8 * 16, out_features=HIDDEN_UNIT), nn.Sigmoid(), nn.Linear(in_features=HIDDEN_UNIT, out_features=8 * 16), nn.Sigmoid())
def forward(self, *x):
x = self.model(x[0])
return x
alphabetdataset = alphabetDataset()
model = alphabet()
data_loader = DataLoader(dataset=alphabetdataset, batch_size=26)
loss_func = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=1.0, momentum=0.9)
for epoch in range(5000):
model.train()
for cnt, data in enumerate(data_loader):
pred = model(data)
acc = ((pred >= 0.5).int() == data).sum() / pred.shape[0] / pred.shape[1]
loss = loss_func(pred, data)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 5000 == 0:
print('epoch: %2d loss: %4f acc: %4f' % (epoch + 1, loss, acc))
with open('ascii_output.txt', 'w', encoding="utf-8") as f:
for alpha_bet_pred in pred:
draw = (alpha_bet_pred >= 0.5).reshape(16, 8)
for draw_line in draw:
for draw_s in draw_line:
if draw_s:
f.write('o')
else:
f.write(' ')
f.write('\n')
f.write('\n')
§05 图像压缩
本题相关代码见q5.py
。下表显示了隐层节点数目和恢复图像质量的关系。恢复的图像可分别查看recover16.bmp
、recover64.bmp
、recover256.bmp
。
import torch
from PIL import Image
from torch import nn
from torch.utils.data import DataLoader, Dataset
from torchvision.transforms import transforms
from torchvision.utils import save_image
HIDDEN_UNIT = 16
class lenaDataset(Dataset):
def __init__(self):
self.dataset = []
img = Image.open('lena512.bmp')
img = transforms.ToTensor()(img)
for init_row in range(64):
for init_col in range(64):
self.dataset.append(img[:, init_row * 8:init_row * 8 + 8, init_col * 8:init_col * 8 + 8])
def __len__(self):
return len(self.dataset)
def __getitem__(self, index):
return self.dataset[index].reshape([-1])
class lena(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(in_features=8 * 8, out_features=HIDDEN_UNIT), nn.Tanh(), nn.Linear(in_features=HIDDEN_UNIT, out_features=8 * 8))
def forward(self, *x):
x = self.model(x[0])
return x
lenadataset = lenaDataset()
model = lena()
data_loader = DataLoader(dataset=lenadataset, batch_size=64 * 64)
loss_func = nn.MSELoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.1, momentum=0.9)
for epoch in range(500):
model.train()
for cnt, data in enumerate(data_loader):
pred = model(data)
loss = loss_func(pred, data)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 100 == 0:
print('epoch: %2d loss: %4f' % (epoch + 1, loss))
recover_img = torch.zeros([1, 512, 512])
for row in range(64):
for col in range(64):
recover_img[:, row * 8:row * 8 + 8, col * 8:col * 8 + 8] = pred[row * 64 + col].reshape([8, 8])
save_image(recover_img, 'recover16.bmp')
▲ 图5.1 隐层节点个数与回复MSE
▲ 图5.2 RECOVER16
▲ 图5.3 RECOVER64
▲ 图5.4 RECOVER256
数值和视觉都表明,其它条件相同的情况下提高隐层节点数目可以提高数据恢复质量。
§06 MNIST
6.1 人工提取特征
本题相关代码见q6_1.py
。经过60
轮训练可在测试集上达到90.0%
的准确率。
import torch
import torch.nn.functional as F
from torch import nn
from torch.utils.data import DataLoader, sampler
from torchvision import datasets, transforms
from torchvision.transforms.functional import resize
train_loader = DataLoader(datasets.MNIST('./mnist_data',
download=True,
train=True,
transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307, ), (0.3081, ))])),
batch_size=1000,
sampler=sampler.SubsetRandomSampler(range(5000)))
test_loader = DataLoader(datasets.MNIST('./mnist_data',
download=True,
train=False,
transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307, ), (0.3081, ))])),
batch_size=2000,
sampler=sampler.SubsetRandomSampler(range(2000)))
class EdgeFilter(nn.Module):
def __init__(self):
super().__init__()
self.kernel = []
self.kernel.append(torch.Tensor([[[[5, 5, 5], [-3, 0, -3], [-3, -3, -3]]]]).cuda())
self.kernel.append(torch.Tensor([[[[-3, -3, -3], [-3, 0, -3], [5, 5, 5]]]]).cuda())
self.kernel.append(torch.Tensor([[[[-3, -3, 5], [-3, 0, 5], [-3, -3, 5]]]]).cuda())
self.kernel.append(torch.Tensor([[[[5, -3, -3], [5, 0, -3], [5, -3, -3]]]]).cuda())
self.kernel.append(torch.Tensor([[[[-3, 5, 5], [-3, 0, 5], [-3, -3, -3]]]]).cuda())
self.kernel.append(torch.Tensor([[[[-3, -3, -3], [5, 0, -3], [5, 5, -3]]]]).cuda())
self.kernel.append(torch.Tensor([[[[-3, -3, -3], [-3, 0, 5], [-3, 5, 5]]]]).cuda())
self.kernel.append(torch.Tensor([[[[5, 5, -3], [5, 0, -3], [-3, -3, -3]]]]).cuda())
self.net = nn.ModuleList([nn.Sequential(nn.Linear(in_features=14 * 14, out_features=8), nn.ReLU())] * 8)
self.net.append(nn.Linear(in_features=16 * 16, out_features=8))
self.cls = nn.Linear(in_features=8 * 9, out_features=10)
def forward(self, *x):
x = resize(x[0], (16, 16))
out = self.net[-1](x.reshape([-1, 16 * 16]))
for kernel_cnt in range(8):
out = torch.cat((out, self.net[kernel_cnt](F.conv2d(x, weight=self.kernel[kernel_cnt]).reshape([-1, 14 * 14]))), dim=1)
return self.cls(out)
model = EdgeFilter().cuda()
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
for epoch in range(100):
model.train()
for cnt, (data, label) in enumerate(train_loader):
data = data.cuda()
label = label.cuda()
pred = model(data)
acc = (pred.max(dim=1)[1] == label).sum() / label.shape[0]
loss = loss_func(pred, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 1 == 0:
model.eval()
with torch.no_grad():
for cnt, (data, label) in enumerate(test_loader):
data = data.cuda()
label = label.cuda()
pred = model(data)
eval_loss = loss_func(pred, label)
eval_acc = (pred.max(dim=1)[1] == label).sum() / label.shape[0]
print('epoch: %2d train_loss: %4f train_acc: %4f eval_loss: %4f eval_acc: %4f' % (epoch + 1, loss, acc, eval_loss, eval_acc))
6.2 图片直接输入
本题相关代码见q6_2.py
。使用具有一个隐层和32
个隐层节点的神经网络,以1000
作为批大小训练60
轮后在测试集上达到96.7%
的准确率。
import torch
from torch import nn
from torch.utils.data import DataLoader
from torchvision import datasets, transforms
HIDDEN_UNIT = 32
train_loader = DataLoader(datasets.MNIST('./mnist_data',
download=True,
train=True,
transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307, ), (0.3081, ))])),
batch_size=1000,
shuffle=True)
test_loader = DataLoader(datasets.MNIST('./mnist_data',
download=True,
train=False,
transform=transforms.Compose([transforms.ToTensor(), transforms.Normalize((0.1307, ), (0.3081, ))])),
batch_size=10000)
class MNIST(nn.Module):
def __init__(self):
super().__init__()
self.model = nn.Sequential(nn.Linear(in_features=784, out_features=HIDDEN_UNIT), nn.ReLU(), nn.Linear(in_features=HIDDEN_UNIT, out_features=10))
def forward(self, *x):
x = self.model(x[0])
return x
model = MNIST().cuda()
loss_func = nn.CrossEntropyLoss()
optimizer = torch.optim.SGD(model.parameters(), lr=0.01, momentum=0.9)
for epoch in range(100):
model.train()
for cnt, (data, label) in enumerate(train_loader):
data = data.cuda()
label = label.cuda()
pred = model(data.reshape([-1, 784]))
acc = (pred.max(dim=1)[1] == label).sum() / label.shape[0]
loss = loss_func(pred, label)
optimizer.zero_grad()
loss.backward()
optimizer.step()
if (epoch + 1) % 1 == 0:
model.eval()
with torch.no_grad():
for cnt, (data, label) in enumerate(test_loader):
data = data.cuda()
label = label.cuda()
pred = model(data.reshape([-1, 784]))
eval_loss = loss_func(pred, label)
eval_acc = (pred.max(dim=1)[1] == label).sum() / label.shape[0]
print('epoch: %2d train_loss: %4f train_acc: %4f eval_loss: %4f eval_acc: %4f' % (epoch + 1, loss, acc, eval_loss, eval_acc))
6.3 讨论
如何在人工提取特征或使用神经网络提取特征中进行选择需要就事论事、因地制宜。人工特征在具有较少训练样本时可发挥先验知识和规则的力量,而神经网络则可以简化特征设计的步骤并利用更丰富的数据达到更好的性能。
※ 总 结 ※
本文给出了 2021年人工神经网络第一次作业要求 中,由同学提交的作业示例。
■ 相关文献链接:
● 相关图表链接:
相关文章
- 2021深圳积分入户,优先选加125分的软考证书
- 2021双十一满减规则活动时间是什么时候?怎么定时提醒自己?
- 2021年中秋节加班工资怎么算?用便签记录工作调休安排
- 云原生实战派:2021 让改变发生,2022 让创新升级
- 漏洞修复--OpenSSH权限提升漏洞(CVE-2021-41617)
- 基于STM32H7的ADS1256驱动案例,8通道,24bit ADC,带可编程增益(2021-09-20)
- 【合集】Jerry Wang 2018~2021 四年期间的 SAP 技术文章合集
- 如何安装最新版本的 SAP ABAP Development Tool ( ADT ) 2021年度更新
- Article:AI领域2021年度总结与2022年度展望:多模态人工智能起飞、万亿参数模型的爆发、生成模型在音乐电影制作上的进展、Transformer架构正在以一己之力统一AI江湖、AI法律监管
- 2021年最新完整统计TensorFlow2.x报错记录与解决方法「希望能帮助到你」
- 2021软件测试面试题(持续更新)
- 2021年OI集训队赛前模拟4题解
- DayDayUp:2021年的自我总结