내 연락처 정보
우편메소피아@프로톤메일.com
2024-07-12
한어Русский языкEnglishFrançaisIndonesianSanskrit日本語DeutschPortuguêsΕλληνικάespañolItalianoSuomalainenLatina
신경망을 더 잘 이해하려면 필기 숫자 인식이라는 작은 작업부터 신경망의 작동 원리와 일반적인 프로세스를 계층별로 이해하는 것이 매우 적절합니다.
이 기사에서는 신경망을 보다 구체적이고 지각적으로 이해하기 위해 표준 피드포워드 신경망을 설계, 구현 및 훈련하는 방법을 설명하기 위해 손글씨로 숫자 인식 작업을 완료합니다.
구체적으로, 우리는 3층 신경망을 설계하고 훈련해야 합니다. 이 신경망은 디지털 이미지를 입력으로 사용합니다. 신경망에서 계산한 후 이미지의 숫자를 식별하여 디지털 이미지의 분류를 실현합니다.
이 과정에서는 신경망의 설계 및 구현, 훈련 데이터의 준비 및 처리, 모델 훈련 및 테스트 프로세스의 세 가지 측면을 주로 설명합니다.
영상 데이터를 처리하기 위한 신경망을 설계하기 위해서는 먼저 입력 영상 데이터의 크기와 형식을 명확히 할 필요가 있다.
우리가 처리할 이미지는 28×28 픽셀 크기(MNIST 데이터세트 자체의 형식)의 회색 채널 이미지입니다.
이 회색 이미지에는 28개가 포함되어 있습니다.28 = 784개의 데이터 포인트, 먼저 1로 평면화해야 합니다.크기가 784인 벡터:
그런 다음 이 벡터를 신경망에 입력합니다. 우리는 3계층 신경망을 사용하여 이미지에 해당하는 벡터 x를 처리합니다. x의 데이터의 각 차원은 784차원 이미지 벡터 x를 수신해야 합니다. 신경망은 뉴런을 수신하므로 입력 레이어에는 784개의 뉴런이 포함됩니다.
숨겨진 레이어는 특징 추출에 사용되어 입력 특징 벡터를 더 높은 수준의 특징 벡터로 처리합니다.
손으로 쓴 숫자 이미지는 복잡하지 않기 때문에 여기서는 히든 레이어의 뉴런 수를 256으로 설정하여 입력 레이어와 히든 레이어 사이에 784*256 크기의 선형 레이어가 있게 됩니다.
784차원 입력 벡터를 256차원 출력 벡터로 변환할 수 있으며, 이는 계속해서 출력 레이어로 전파됩니다.
디지털 이미지는 궁극적으로 0부터 9까지 가능한 10개의 숫자로 인식되므로 출력 레이어에서는 이 10개의 숫자에 해당하는 10개의 뉴런을 정의해야 합니다.
히든 레이어와 출력 레이어 사이의 선형 레이어를 통해 256차원 벡터를 계산한 후 10차원 출력 결과를 얻습니다. 이 10차원 벡터는 10개 숫자의 예측 점수를 나타냅니다.
계속해서 10개의 숫자에 대한 예측 확률을 얻으려면 출력 레이어의 출력을 소프트맥스 레이어에 입력해야 합니다. 소프트맥스 레이어는 10차원 벡터를 각각 10개의 확률 값 P0에서 P9로 변환합니다. 확률 값은 숫자에 해당합니다. 즉, 입력 이미지가 특정 숫자일 가능성은 P0부터 P9까지의 10개의 확률 값의 합이 1입니다. 이는 의 속성에 의해 결정됩니다. 소프트맥스 기능:
이상이 신경망의 설계 아이디어입니다. 다음으로 PyTorch 프레임워크를 사용하여 구현합니다.
먼저 신경망을 구현합니다.
코드는 아래와 같이 표시됩니다.
import torch
from torch import nn
# 定义神经网络
class NetWork(nn.Module):
def __init__(self):
super().__init__()
# 线性层1,输入层和隐藏层之间的线性层
self.layer1 = nn.Linear(784, 256)
# 线性层2,隐藏层和输出层之间的线性层
self.layer2 = nn.Linear(256, 10)
# 这里没有直接定义 softmax 层
# 这是因为后面会使用 CrossEntropyLoss 损失函数
# 在这个损失函数中会实现 softmax 的计算
def forward(self, x):
x = x.view(-1, 28 * 28) # 使用view 函数将 x 展平
x = self.layer1(x) # 将 x 输入至 layer1
x = torch.relu(x) # 使用 ReLu 函数激活
return self.layer2(x) # 输入至 layer2 计算结果
다음으로 데이터세트를 준비합니다.
데이터 세트를 얻으려면 다음 방법을 사용하여 PyTorch 공식 웹사이트에서 다운로드할 수도 있습니다.
# 准备数据集
train_data = torchvision.datasets.MNIST(root='data', train=True, download=True)
test_data = torchvision.datasets.MNIST(root='data', train=False, download=True)
이러한 방식으로 다운로드된 데이터는 train_data 및 test_data에 자동으로 저장됩니다. 이에 따라 도구 패키지는 코드에서 지정한 디렉터리에 다운로드됩니다.
그러나 이는 보편적인 방법이 아닙니다. 향후 작업과 연구에서는 우리가 직접 운영하고 처리해야 하는 데이터 세트가 많을 것이므로 여기서는 보다 일반적인 방법을 소개합니다. 이는 공식 웹사이트에서 기본 데이터를 다운로드하는 것입니다. 데이터 세트는 예, 이미지 묶음입니다!
다운로드한 데이터를 다음 두 폴더에 저장합니다.
우리는 데이터를 각각 train과 test라는 두 디렉터리에 저장합니다. 여기서 train에는 60,000개의 데이터가 있고 test에는 10,000개의 데이터가 있으며, 이는 각각 모델 훈련과 테스트에 사용됩니다.
train 및 test 디렉터리 모두 10개의 하위 디렉터리를 포함하며, 하위 디렉터리의 이름은 이미지의 숫자에 해당합니다. 예를 들어, 숫자 3의 이미지는 3이라는 폴더에 저장됩니다.
여기서 이미지 이름은 임의의 문자열 서명입니다.
데이터 준비가 완료되면 데이터 읽기 기능이 구현됩니다. 초보자는 이 부분을 학습할 때 일반적인 데이터 처리 프로세스만 알면 됩니다.
코드는 다음과 같이 구현됩니다.
# 首先实现图像的预处理pipeline
transform = torchvision.transforms.Compose([
torchvision.transforms.Grayscale(num_output_channels=1), # 转换为单通道灰度图像
torchvision.transforms.ToTensor() # 转换为PyTorch支持的张量
])
# 这是方式一准备数据集的方式嗷
train_data = torchvision.datasets.MNIST(root='data', train=True, download=True, transform=transform)
test_data = torchvision.datasets.MNIST(root='data', train=False, download=True, transform=transform)
# 下面这是方式二准备数据集的方式
# 使用 ImageFolder 函数读取数据文件夹,构建数据集 dataset
# 这个函数会将保存数据的文件夹的名字,作为数据的标签,组织数据
# 例如,对于名字为 3 的文件夹
# 就会将 3 作为文件夹中图像数据的标签,和图像配对用于后续的训练,使用起来非常方便
train_dataset = torchvision.datasets.ImageFolder(root='./mnist/train', transform=transform)
test_dataset = torchvision.datasets.ImageFolder(root='./mnist/test', transform=transform)
# 不管使用哪种准备数据集的方式,最后的效果都是一样的
# 打印它们的长度看一下
print(len(train_data))
print(len(test_data))
실행 결과를 살펴보십시오.
훈련 데이터와 테스트 데이터가 모두 얻어졌음을 알 수 있는데, 이는 앞서 말한 것과 완전히 일치합니다.
그런 다음 train_loader를 사용하여 소규모 배치 데이터 읽기를 구현합니다.
# 使用 train_loader 实现小批量的数据读取
# 这里设置小批量的大小,batch_size = 64。
# 也就是每个批次包括 64 个数据
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
# 打印 train_loader 的长度
print(" train loader length: ", len(train_loader))
# 60000 个训练数据,如果每个小批量读入 64 个样本,那么 60000 个数据会被分为 938 组
# 计算 938 * 64 = 60032,这说明最后一组会不够 64 个数据
실행 결과는 다음과 같습니다.
그런 다음 train_loader를 반복하여 각 미니 배치 데이터를 얻을 수 있습니다.
# 循环遍历 train_loader
# 每一次循环,都会取出 64 个图像数据,作为一个小批量 batch
for batch_idx, (data, label) in enumerate(train_loader):
if batch_idx == 3: # 打印前三个 batch 观察
break
print("batch_idx: ", batch_idx)
print("data.shape: ", data.shape) # 数据的尺寸
print("label: ", label.shape) # 图像中的数字
print(label)
다음은 위의 루프 문에 대한 간단한 설명입니다.
낱낱이 세다(): 이것은 탐색 가능한 데이터 객체(예: 목록, 튜플 또는 문자열)를 인덱스 시퀀스로 결합하고 데이터와 데이터 첨자를 동시에 나열하는 데 사용되는 Python의 내장 함수입니다. 인덱스와 값을 동시에. 여기서는 train_loader의 각 배치를 반복하는 데 사용됩니다. 여기서 배치_idx는 현재 배치의 인덱스(0부터 시작)이고, (data, label)은 현재 배치의 데이터 및 레이블입니다.
batch_idx, (data, label)에 대해 enumerate(train_loader)에서:: 이 루프 문의 의미는 train_loader의 각 배치에 대해 루프 본문의 코드가 실행된다는 것입니다.각 루프 반복에서 bat_idx는 현재 배치의 인덱스이고, (data, label)은 현재 배치의 데이터 및 레이블입니다. . 데이터는 일반적으로 여러 데이터 포인트를 포함하는 텐서이며, 각 데이터 포인트는 샘플입니다. 레이블은 지도 학습의 목표 값에 사용되는 이러한 데이터 포인트에 해당하는 레이블 텐서입니다.
실행 효과는 다음과 같습니다.
실행 결과에서 볼 수 있습니다.
1. Batch_idx = 0은 데이터의 첫 번째 배치임을 의미합니다.
2. data.shape는 데이터의 크기가 [64, 1, 28, 28]임을 나타냅니다.
위의 크기는 각 데이터 배치에 64개의 이미지가 포함되고, 각 이미지에 1개의 회색 채널이 있으며, 이미지 크기가 28*28임을 의미합니다.
3. label.shape는 배치에 64개의 숫자가 있고 이에 해당하는 총 레이블 수가 64개라는 것을 의미합니다. 각 숫자에는 레이블이 있습니다.
차이점에 주의하세요. 실제 라벨 카테고리는 9개만 있어야 합니다. 왜냐하면 숫자는 1부터 9까지만 있고 여기서는 라벨 값이 64개라는 뜻입니다.
4. 텐서 배열은 이러한 64개의 디지털 이미지 각각에 해당하는 레이블 값을 나타냅니다.
이전 준비가 완료되면 모델 학습 및 테스트를 시작할 수 있습니다.
훈련 코드는 다음과 같습니다.
# 在使用 PyTorch 训练模型时,需要创建三个对象
model = NetWork() # 1、模型本身,它就是我们设计的神经网络
optimizer = torch.optim.Adam(model.parameters()) # 2、优化器,优化模型中的参数
criterion = nn.CrossEntropyLoss() # 3、损失函数,分类问题使用交叉熵损失误差
# 开始训练模型
for epoch in range(10): # 外层循环,代表了整个训练数据集的遍历次数
# 整个训练集要循环多少轮,是10次还是20次还是100次都是有可能的
# 内层循环使用train_loader 进行小批量的数据读取
for batch_idx, (data, label) in enumerate(train_loader):
# 内层每循环一次,就会进行一次梯度下降算法
# 包括五个步骤:
output = model(data) # 1、计算神经网络的前向传播结果
loss = criterion(output, label) # 2、计算 output 和标签 label 之间的误差损失 loss
loss.backward() # 3、使用 backward 计算梯度
optimizer.step() # 4、使用 optimizer.step 更新参数
optimizer.zero_grad() # 5、将梯度清零
# 这五个步骤是使用 PyTorch 框架训练模型的定式,初学的时候记住就可以了
# 每迭代 100 个小批量,就打印一次模型的损失,观察训练的过程
if batch_idx % 100 == 0:
print(f"Epoch {epoch + 1} / 10 "
f"| Batch {batch_idx} / {len(train_loader)}"
f"| Loss: {loss.item():.4f}")
torch.save(model.state_dict(), 'mnist.pth') # 最后保存训练好的模型
실행 효과는 다음과 같습니다.
중간 생략...
최종 손실값은 0.0239로 매우 작음을 알 수 있습니다.
마지막 단계는 테스트입니다. 테스트 과정은 기본적으로 훈련과 동일합니다.
model = NetWork() # 定义神经网络模型
model.load_state_dict(torch.load('mnist.pth')) # 加载刚刚训练好的模型文件
right = 0 # 保存正确识别的数量
for i, (x, y) in enumerate(test_data):
output = model(x) # 将其中的数据 x 输入到模型中
predict = output.argmax(1).item() # 选择概率最大的标签作为预测结果
# 对比预测值 predict 和真实标签 y
if predict == y:
right += 1
else:
# 将识别错误的样例打印出来
print(f"wrong case: predict = {predict}, but y = {y}")
# 计算出测试结果
sample_num = len(test_data)
accuracy = right * 1.0 / sample_num
print("test accuracy = %d / %d = %.3lf" % (right, sample_num, accuracy))
실행 결과는 다음과 같습니다.
테스트 정확도는 98%로 여전히 매우 높다는 것을 알 수 있다.
위는 처음부터 신경망을 설계하고 훈련하는 과정입니다.
위 내용을 각 기능 부분별로 설명하고 설명하는데 다소 헷갈릴 수 있으니 위의 코드를 다음과 같이 캡슐화합니다.
import torch
import torchvision.datasets
from torch import nn
# ----------------1、定义神经网络-------------------
class NetWork(nn.Module):
def __init__(self):
super().__init__()
# 线性层1,输入层和隐藏层之间的线性层
self.layer1 = nn.Linear(784, 256)
# 线性层2,隐藏层和输出层之间的线性层
self.layer2 = nn.Linear(256, 10)
# 这里没有直接定义 softmax 层
# 这是因为后面会使用 CrossEntropyLoss 损失函数
# 在这个损失函数中会实现 softmax 的计算
def forward(self, x):
x = x.view(-1, 28 * 28) # 使用view 函数将 x 展平
x = self.layer1(x) # 将 x 输入至 layer1
x = torch.relu(x) # 使用 ReLu 函数激活
return self.layer2(x) # 输入至 layer2 计算结果
# ----------------2、图像预处理-------------------
# 实现图像的预处理的pipeline
transform = torchvision.transforms.Compose([
torchvision.transforms.Grayscale(num_output_channels=1), # 转换为单通道灰度图像
torchvision.transforms.ToTensor() # 转换为PyTorch支持的张量
])
# ----------------3、数据集准备-------------------
# 准备训练数据集
train_data = torchvision.datasets.MNIST(root='data', train=True, download=True, transform=transform)
# ----------------4、数据集加载-------------------
# 使用 train_loader 实现小批量的数据读取
# 这里设置小批量的大小,batch_size = 64。
# 也就是每个批次包括 64 个数据
train_loader = torch.utils.data.DataLoader(train_data, batch_size=64, shuffle=True)
# ----------------5、训练神经网络-------------------
# 在使用 PyTorch 训练模型时,需要创建三个对象
model = NetWork() # 1、模型本身,它就是我们设计的神经网络
optimizer = torch.optim.Adam(model.parameters()) # 2、优化器,优化模型中的参数
criterion = nn.CrossEntropyLoss() # 3、损失函数,分类问题使用交叉熵损失误差
# 开始训练模型
for epoch in range(10): # 外层循环,代表了整个训练数据集的遍历次数
# 整个训练集要循环多少轮,是10次还是20次还是100次都是有可能的
# 内层循环使用train_loader 进行小批量的数据读取
for batch_idx, (data, label) in enumerate(train_loader):
# 内层每循环一次,就会进行一次梯度下降算法
# 包括五个步骤:
output = model(data) # 1、计算神经网络的前向传播结果
loss = criterion(output, label) # 2、计算 output 和标签 label 之间的误差损失 loss
loss.backward() # 3、使用 backward 计算梯度
optimizer.step() # 4、使用 optimizer.step 更新参数
optimizer.zero_grad() # 5、将梯度清零
# 这五个步骤是使用 PyTorch 框架训练模型的定式,初学的时候记住就可以了
# 每迭代 100 个小批量,就打印一次模型的损失,观察训练的过程
if batch_idx % 100 == 0:
print(f"Epoch {epoch + 1} / 10 "
f"| Batch {batch_idx} / {len(train_loader)}"
f"| Loss: {loss.item():.4f}")
torch.save(model.state_dict(), 'mnist.pth') # 最后保存训练好的模型
import torch
import torchvision.datasets
from torch import nn
# ----------------1、定义神经网络-------------------
class NetWork(nn.Module):
def __init__(self):
super().__init__()
# 线性层1,输入层和隐藏层之间的线性层
self.layer1 = nn.Linear(784, 256)
# 线性层2,隐藏层和输出层之间的线性层
self.layer2 = nn.Linear(256, 10)
# 这里没有直接定义 softmax 层
# 这是因为后面会使用 CrossEntropyLoss 损失函数
# 在这个损失函数中会实现 softmax 的计算
def forward(self, x):
x = x.view(-1, 28 * 28) # 使用view 函数将 x 展平
x = self.layer1(x) # 将 x 输入至 layer1
x = torch.relu(x) # 使用 ReLu 函数激活
return self.layer2(x) # 输入至 layer2 计算结果
# ----------------2、图像预处理-------------------
# 实现图像的预处理的pipeline
transform = torchvision.transforms.Compose([
torchvision.transforms.Grayscale(num_output_channels=1), # 转换为单通道灰度图像
torchvision.transforms.ToTensor() # 转换为PyTorch支持的张量
])
# ----------------3、数据集准备-------------------
# 准备测试数据集
test_data = torchvision.datasets.MNIST(root='data', train=False, download=True, transform=transform)
# ----------------4、测试神经网络-------------------
model = NetWork() # 定义神经网络模型
model.load_state_dict(torch.load('mnist.pth')) # 加载刚刚训练好的模型文件
right = 0 # 保存正确识别的数量
for i, (x, y) in enumerate(test_data):
output = model(x) # 将其中的数据 x 输入到模型中
predict = output.argmax(1).item() # 选择概率最大的标签作为预测结果
# 对比预测值 predict 和真实标签 y
if predict == y:
right += 1
else:
# 将识别错误的样例打印出来
print(f"wrong case: predict = {predict}, but y = {y}")
# 计算出测试结果
sample_num = len(test_data)
accuracy = right * 1.0 / sample_num
print("test accuracy = %d / %d = %.3lf" % (right, sample_num, accuracy))