从细节过渡到实例 一天学会Pytorch(下)

简介: 从细节过渡到实例 一天学会Pytorch(下)

3. 神经网络要素


3.1. 构建网络


(1) 使用torch.nn模块构建神经网络


关于torch.nn模块包含的全部方法在官方文档 torch.nn 中有详细介绍。翻译版可以在 PyTorch中的torch.nn模块使用详解 中查看


import torch
import torch.nn as nn
import torch.nn.functional as F
class Net(nn.Module):
    #定义Net的初始化函数,这个函数定义了该神经网络的基本结构
    def __init__(self):
        super(Net, self).__init__() #复制并使用Net的父类的初始化方法,即先运行nn.Module的初始化函数
        self.conv1 = nn.Conv2d(3, 6, 5) # 定义二维卷积层:输入为3通道图像,输出6个特征图, 卷积核为5x5正方形
        self.conv2 = nn.Conv2d(6, 16, 5)# 定义二维卷积层:输入为6张特征图,输出16个特征图, 卷积核为5x5正方形
        self.fc1   = nn.Linear(16*5*5, 120) # 定义线性全连接层:y = Wx + b,并将16*5*5个特征连接到120个节点上
        self.fc2   = nn.Linear(120, 84)#定义线性全连接层:y = Wx + b,并将120个节点连接到84个节点上
        self.fc3   = nn.Linear(84, 10)#定义线性全连接层:y = Wx + b,并将84个节点连接到10个节点上
    #定义该神经网络的向前计算函数,该函数定义成功后,会自动生成反向传播函数(autograd)
    def forward(self, x):
        x = F.max_pool2d(F.relu(self.conv1(x)), (2, 2)) #输入x经过卷积conv1之后,经过激活函数ReLU(原来这个词是激活函数的意思),使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = F.max_pool2d(F.relu(self.conv2(x)), 2) #输入x经过卷积conv2之后,经过激活函数ReLU,使用2x2的窗口进行最大池化Max pooling,然后更新到x。
        x = x.view(-1, 16*5*5) #view函数将张量x变形成一维的向量形式,总特征数并不改变,为接下来的全连接作准备,可验算这里的-1值为32。。
        x = F.relu(self.fc1(x)) #输入x经过全连接1,再经过ReLU激活函数处理,然后更新x
        x = F.relu(self.fc2(x)) #输入x经过全连接2,再经过ReLU激活函数处理,然后更新x
        x = self.fc3(x) #输入x经过全连接3处理,然后更新x
        return x


(2) 查看神经网络的参数


# 实例化一个神经网络
net = Net()
layers = list(net.parameters())
# 查看神经网络的基本结构信息
print(net)
'''
Net(
  (conv1): Conv2d(3, 6, kernel_size=(5, 5), stride=(1, 1))
  (conv2): Conv2d(6, 16, kernel_size=(5, 5), stride=(1, 1))
  (fc1): Linear(in_features=400, out_features=120, bias=True)
  (fc2): Linear(in_features=120, out_features=84, bias=True)
  (fc3): Linear(in_features=84, out_features=10, bias=True)
)
'''
# 查看神经网络的总层数
print(len(layers)) 
'''
10
'''
# 查看最后一层的参数
print(layers[-1]) 
'''
Parameter containing:
tensor([-0.0674,  0.0600,  0.0800, -0.0760,  0.0293,  0.0745,  0.0182,  0.0616,
        -0.0197,  0.0729], requires_grad=True)
'''
# 查看第一层的大小
print(layers[0].size()) 
'''
torch.Size([6, 3, 5, 5])
'''
# 查看每一层的参数和节点数量
total_parameter=0
layer_num = 1
for layer in layers:
    parameter = 1
    for _ in layer.size():
        parameter *= _
    print("第" + str(layer_num) + "层的结构:"+ str(list(layer.size())) + ",参数和:"+ str(parameter))
    total_parameter = total_parameter + parameter
    layer_num += 1
print("总参数和:"+ str(total_parameter))
'''
第1层的结构:[6, 3, 5, 5],参数和:450
第2层的结构:[6],参数和:6
第3层的结构:[16, 6, 5, 5],参数和:2400
第4层的结构:[16],参数和:16
第5层的结构:[120, 400],参数和:48000
第6层的结构:[120],参数和:120
第7层的结构:[84, 120],参数和:10080
第8层的结构:[84],参数和:84
第9层的结构:[10, 84],参数和:840
第10层的结构:[10],参数和:10
总参数和:62006
Process finished with exit code 0
'''


(3) 查看前向计算过程


# 实例化一个神经网络
net = Net()
input = torch.randn(2, 3, 32, 32) # 产生2个3通道,32*32的随机输入,这是nn.Conv2d的接收格式
out = net(input)
print(out)
'''
tensor([[-0.1063,  0.0641, -0.0391, -0.0517,  0.1174, -0.0600,  0.0044, -0.0311,
         -0.1074,  0.0226],
        [-0.0779,  0.0697, -0.0486, -0.0842,  0.1377, -0.0276, -0.0247, -0.0504,
         -0.1054,  0.0065]], grad_fn=<AddmmBackward>)
'''


(4) 查看反向传播过程


net = Net() # 实例化一个神经网络
net.zero_grad() # 梯度初始化
input = torch.randn(1, 3, 32, 32) 
out = net(input)
out.backward(torch.randn(1, 10)) # 随机选取参数进行反向传播
print(out)
'''
tensor([[-0.0829,  0.0556, -0.0088, -0.0263, -0.0518,  0.0802, -0.0923,  0.0091,
          0.0122,  0.0927]], grad_fn=<AddmmBackward>)
'''


3.2. 损失函数


(1) 定义损失函数并计算损失


net = Net()
criterion = nn.MSELoss() # 定义均方误差损失函数
target = torch.randn(10).view(1, -1)  # 定义10个随机真值(因为网络最后一层有10个输出),并转换为行向量
print(target)
'''
tensor([[-1.1115, -0.3807,  0.5877, -1.0567, -0.0541, -0.3390, -1.9487, -0.2775,
         -0.0366,  0.7521]])
'''
output = net(torch.randn(1, 3, 32, 32))  # 用随机输入计算输出
loss = criterion(output, target)  # 计算损失
print(output)
print(loss)
'''
tensor([[ 0.0881, -0.0362, -0.1039, -0.0116,  0.0952,  0.0953, -0.0499,  0.0214,
         -0.0549, -0.0493]], grad_fn=<AddmmBackward>)
tensor(0.7676, grad_fn=<MseLossBackward>)
'''


PyTorch的损失函数有十九种,可以在官方文档 PyTorch Loss-Functions 中查看,中文译版可以在博客 Pytorch学习之十九种损失函数 中查看,常用的损失函数如下:


描述 损失函数

L1损失 L1Loss

平滑L1损失 SmoothL1Loss

均方误差损失 MSELoss

交叉熵损失 CrossEntropyLoss

KL散度损失 KLDivLoss

余弦损失 CosineEmbeddingLoss

二分类逻辑损失 SoftMarginLoss

负对数似然损失 NLLLoss

二维负对数似然损失 NLLLoss2d

泊松负对数似然损失 PoissonNLLLoss

(2) 计算损失的反向传播


net = Net()
net.zero_grad() # 梯度初始化
criterion = nn.MSELoss() # 定义均方误差损失函数
target = torch.randn(10).view(1, -1)  # 定义10个随机真值(因为网络最后一层有10个输出),并转换为行向量
output = net(torch.randn(1, 3, 32, 32))  # 用随机输入计算输出
loss = criterion(output, target)  # 计算损失
loss.backward() # 损失反向传播
print('conv1.bias.grad before backward: ' + str(net.conv1.bias.grad))
print('conv2.bias.grad before backward: ' + str(net.conv2.bias.grad))
print('fc3.bias.grad before backward: ' + str(net.fc3.bias.grad))
'''
conv1.bias.grad before backward: tensor([ 0.0213, -0.0110,  0.0120, -0.0252, -0.0081,  0.0115])
conv2.bias.grad before backward: tensor([ 0.0169,  0.0230,  0.0039, -0.0125,  0.0182,  0.0000, -0.0253,  0.0000, -0.0133, -0.0038,  0.0196, -0.0379, -0.0142, -0.0147, -0.0534,  0.0265])
fc3.bias.grad before backward: tensor([ 0.2603, -0.1132,  0.0708,  0.1399, -0.2388,  0.1579, -0.0635,  0.0143, -0.5937,  0.1236])
'''


3.3. 优化器


优化器用于管理并更新模型中可学习参数(权值、偏置bias)的值。


(1) 定义优化器算法,并使用优化器更新权重


net = Net()
net.zero_grad() # 梯度初始化
criterion = nn.MSELoss() # 定义均方误差损失函数
optimizer = optim.SGD(net.parameters(), lr=0.01) # 定义随机梯度下降优化算法,并设置学习率为0.01
optimizer.zero_grad() # 优化器梯度初始化
target = torch.randn(10).view(1, -1)  # 定义10个随机真值(因为网络最后一层有10个输出),并转换为行向量
output = net(torch.randn(1, 3, 32, 32))  # 用随机输入计算输出
loss = criterion(output, target)  # 计算损失
loss.backward() # 损失反向传播
optimizer.step() # 对网络模型参数进行优化
print('conv1.bias.grad before backward: ' + str(net.conv1.bias.grad))
print('conv2.bias.grad before backward: ' + str(net.conv2.bias.grad))
print('fc3.bias.grad before backward: ' + str(net.fc3.bias.grad))
print(loss)
'''
conv1.bias.grad before backward: tensor([ 0.0046,  0.0145, -0.0112, -0.0003,  0.0035,  0.0078])
conv2.bias.grad before backward: tensor([-0.0040, -0.0106,  0.0092,  0.0102,  0.0140, -0.0078, -0.0187, -0.0118,
        -0.0066, -0.0005, -0.0054,  0.0032,  0.0016,  0.0033, -0.0020, -0.0043])
fc3.bias.grad before backward: tensor([ 0.0078, -0.0456,  0.0653, -0.0499,  0.2710, -0.1554,  0.0496, -0.2634,
        -0.0601,  0.0723])
tensor(0.4679, grad_fn=<MseLossBackward>)
'''


PyTorch的各类优化器可以在官方文档 PyTorch TORCH.OPTIM 中查看,中文译版可以在博客 Pytorch的优化器总结 中查看,常用的优化器如下:


image.png


3.4. 模型存取


(1) 保存训练好的模型


# 实例化一个神经网络
net = Net()
# 方法一,保存整个网络
torch.save(net, './my_net.pth')
# 方法二,保存网络的状态信息
torch.save(net.state_dict(), './my_net.pth')


(2) 读取保存的模型


# 提取整个网络
pretrained_net = torch.load('./my_net.pth')
# 提取网络状态
net_new = Net()
net_new.load_state_dict(torch.load('./my_net.pth'))


4. 神经网络实例


4.1. 分类神经网络


import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 构造数据
n_data = torch.ones(100, 2)
x0 = torch.normal(3*n_data, 1)
x1 = torch.normal(-3*n_data, 1)
# 标记为y0=0,y1=1两类标签
y0 = torch.zeros(100)
y1 = torch.ones(100)
# 通过.cat连接数据
x = torch.cat((x0, x1), 0).type(torch.float)
y = torch.cat((y0, y1), 0).type(torch.long)
# 构造一个简单的神经网络
class Net(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()
        self.inLayer = torch.nn.Linear(n_feature, n_hidden) # 输入层
        self.hiddenLayer = torch.nn.Linear(n_hidden, n_hidden) # 隐藏层
        self.outLayer = torch.nn.Linear(n_hidden, n_output) # 输出层
    # 前向计算函数,定义完成后会隐式地自动生成反向传播函数
    def forward(self, x):
        x = F.relu(self.hiddenLayer(self.inLayer(x)))
        x = self.outLayer(x)
        return x
net = Net(2, 10, 2) # 初始化一个网络,2个输入层节点,10个隐藏层节点,2个输出层节点
loss_func = torch.nn.CrossEntropyLoss() # 定义交叉熵损失函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.2) # 配置网络优化器
# 将网络模型、损失函数和输入张量迁入GPU
if(torch.cuda.is_available()):
    net = net.cuda()
    loss_func = loss_func.cuda()
    x, y = x.cuda(), y.cuda()
# 训练模型
out = net(x)
for t in range(300):
    out = net(x) # 将数据输入网络,得到输出
    loss = loss_func(out, y) # 得到损失
    optimizer.zero_grad() # 梯度初始化
    loss.backward() # 反向传播
    optimizer.step() # 对网络进行优化
# 使用模型进行预测
prediction = torch.max(F.softmax(out, dim=0), 1)[1]
pred_y = prediction.data.cpu().numpy().squeeze()
# 可视化
plt.scatter(x.data.cpu().numpy()[:, 0], x.data.cpu().numpy()[:, 1], c=pred_y, s=100, lw=0, cmap='RdYlBu')
plt.show()


4.2. 回归神经网络


import torch
import torch.nn.functional as F
import matplotlib.pyplot as plt
# 构造数据
x = torch.unsqueeze(torch.linspace(-1, 1, 100), dim=1)
y = x.pow(2) + 0.2 * torch.rand(x.size())
# 构造一个简单的神经网络
class Net(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()
        self.inLayer = torch.nn.Linear(n_feature, n_hidden) # 输入层
        self.hiddenLayer = torch.nn.Linear(n_hidden, n_hidden) # 隐藏层
        self.outLayer = torch.nn.Linear(n_hidden, n_output) # 输出层
    # 前向计算函数,定义完成后会隐式地自动生成反向传播函数
    def forward(self, x):
        x = F.relu(self.hiddenLayer(self.inLayer(x)))
        x = self.outLayer(x)
        return x
net = Net(1, 10, 1) # 初始化一个网络,1个输入层节点,10个隐藏层节点,1个输出层节点
loss_func = torch.nn.MSELoss() # 定义均方误差损失函数
optimizer = torch.optim.SGD(net.parameters(), lr=0.2) # 配置网络优化器
# 将网络模型、损失函数和输入张量迁入GPU
if(torch.cuda.is_available()):
    net = net.cuda()
    loss_func = loss_func.cuda()
    x, y = x.cuda(), y.cuda()
# 训练模型
out = net(x)
for t in range(300):
    out = net(x) # 将数据输入网络,得到输出
    loss = loss_func(out, y) # 得到损失
    optimizer.zero_grad() # 梯度初始化
    loss.backward() # 反向传播
    optimizer.step() # 对网络进行优化
# 可视化
plt.scatter(x.data.cpu().numpy(), y.data.cpu().numpy())
plt.plot(x.data.cpu().numpy(), out.data.cpu().numpy(), 'r-', lw=5)
plt.show()


4.3. 多分类神经网络


import numpy as np
import sys
import torch.nn.functional as F
import torch.utils.data as Data
import torch
import matplotlib.pyplot as plt
sys.path.append('./')
# 构造一个简单的神经网络
class Net(torch.nn.Module):
    def __init__(self, n_feature, n_hidden, n_output):
        super(Net, self).__init__()
        self.inLayer = torch.nn.Linear(n_feature, n_hidden) # 输入层
        self.hiddenLayer = torch.nn.Linear(n_hidden, n_hidden) # 隐藏层
        self.outLayer = torch.nn.Linear(n_hidden, n_output) # 输出层
    # 前向计算函数,定义完成后会隐式地自动生成反向传播函数
    def forward(self, x):
        x = self.inLayer(x)
        x = F.relu(self.hiddenLayer(x))
        x = self.outLayer(x)
        return x
# 读取本地数据文件
def loadData(path):
    # delimiter用于设置分隔符,如果是CSV文件那么 delimiter=','
    dataset_df = np.loadtxt(path, dtype=int, delimiter=' ')
    return dataset_df
def show_curve(ys, title):
    '''
    画图
    :param ys: 损失或F1值数据
    :param title: 标题
    :return:
    '''
    x = np.array(range(len(ys)))
    y = np.array(ys)
    plt.plot(x, y, c='b')
    plt.axis()
    plt.title('{} curve'.format(title))
    plt.xlabel('epoch')
    plt.ylabel('{}'.format(title))
    plt.show()
    plt.savefig(fname= title + ".png", dpi=600)
    plt.savefig(fname=title + ".png")
    plt.clf()
def fit(model, loss_func, data_loader, test_data_loader, num_epochs, optimizer):
    """
    进行训练和测试,训练结束后显示损失和准确曲线,并保存模型
    参数:
        model: CNN 网络
        num_epochs: 训练epochs数量
        optimizer: 损失函数优化器
    """
    losses = []
    f1s = []
    for epoch in range(num_epochs):
        print('Epoch {}/{}:'.format(epoch + 1, num_epochs))
        # 训练
        loss = train(model, data_loader, loss_func, optimizer)
        losses.append(loss)
        # 验证
        # 加载模型
        # model = torch.load('./my_net.pth')
        F1 = evaluate(model, test_data_loader)
        f1s.append(F1)
        print("------ Epoch END ------")
    # 损失函数曲线和准确率曲线
    show_curve(losses, "train loss")
    show_curve(f1s, "validation F1")
def train(model, train_loader, loss_func, optimizer):
    """
    训练模块
    model: CNN 网络
    train_loader: 训练数据的Dataloader
    loss_func: 损失函数
    device: 训练所用的设备
    """
    total_loss = 0
    model.train() # 切换至训练模式
    # 批次训练
    for i, (data_tensor, labels) in enumerate(train_loader):
        # 前向传播
        outputs = model(data_tensor)
        loss = loss_func(outputs, labels)
        # 反向传播和优化
        optimizer.zero_grad()
        loss.backward(retain_graph=True)
        optimizer.step()
        total_loss += loss.item()
    # 输出总loss
    print("Train Loss: {:.4f}".format(total_loss))
    return total_loss
def evaluate(model, test_data_loader):
    """
    测试模块,这里使用test代替validation
    model: CNN 网络
    val_loader: 验证集的Dataloader
    device: 训练所用的设备
    return:准确率
    """
    # # 切换至评估模式
    model.eval()
    with torch.no_grad():
        TP = 0 # 预测正确的正样本(1->1)
        FP = 0 # 预测错误的正样本(0->1)
        FN = 0 # 预测错误的负样本(1->0)
        for i, (data_tensor, labels) in enumerate(test_data_loader):
            outputs = model(data_tensor)
            # 选取最大输出值的类别进行分类
            _, predicted = torch.max(outputs.data, dim=1)
            # 根据几个类别的输出值赋予相对应的概率,然后根据概率值进行分类
            # _ = F.softmax(outputs.data, dim=1)
            # predicted = Categorical(_).sample()
            # 输出神经网络的预测值与实际label,比较预测结果
            # print(str(i+1) + " Predicted: " + str(predicted))
            # print(str(i+1) + " Label: " + str(labels))
            for j in range(len(predicted)):
                if (labels[j] == 1) and (predicted[j] == labels[j]):
                    TP += 1
                if (labels[j] == 1) and (predicted[j] != labels[j]):
                    FN += 1
                if (labels[j] == 0) and (predicted[j] != labels[j]):
                    FP += 1
        if (TP + FP) == 0: # 精确率
            precision = 0
        else:
            precision = TP / (TP + FP)
        if (TP + FN) == 0: # 召回率
            recall = 0
        else:
            recall = TP / (TP + FN)
        if (precision + recall) == 0: # F1
            F1 = 0
        else:
            F1 = (2 * precision * recall) / (precision + recall)
        print('Precision on Test Set: {:.4f} %'.format(100 * precision))
        print('Recall on Test Set: {:.4f} %'.format(100 * recall))
        print('F1 on Test Set: {:.4f} %'.format(100 * F1))
        return F1
if __name__ == "__main__":
    # ------ 构造训练数据 ------ #
    n_data = torch.ones(1000, 2) # 1000行2列的矩阵,即1000个二维坐标点
    x0 = torch.normal(3 * n_data, 1) # 给原二维坐标点加正太扰动,x0在第一象限
    x1 = torch.normal(-3 * n_data, 1) # 给原二维坐标点加正太扰动,x1在第三象限
    x = x0 + x1 # 拼接数据
    # 构造label,标记为y0=0,y1=1两类标签
    y0 = torch.zeros(1000) # 1000个0
    y1 = torch.ones(1000) # 1000个1
    y = y0 + y1 # 拼接数据
    # ------ 将数据载入DataLoader ------ #
    x_tensor = torch.Tensor(x).type(torch.float)
    y_tensor = torch.Tensor(y).type(torch.long)  # label不能是浮点数
    torch_dataset = Data.TensorDataset(x_tensor, y_tensor)
    data_loader = Data.DataLoader(  # 训练数据
        dataset=torch_dataset,
        batch_size=32,  # 从torch_dataset中每次抽出batch size个样本
        shuffle=True  # 随机排序
    )
    # 构建测试数据加载器(data+label)
    torch_test_dataset = Data.TensorDataset(x_tensor, y_tensor)
    test_data_loader = Data.DataLoader(  # 测试数据
        dataset=torch_dataset,
        batch_size=len(torch_test_dataset),  # 从torch_dataset中每次抽出全部样本
        shuffle=False  # 不随机排序
    )
    # ------ 网络参数定义 ------ #
    # 输入数据的维度即输入层的维度,这里是2,因为坐标点是二维的
    input_layer_size = len(x[0])
    # 初始化一个网络,input_layer_size个输入层节点,256个隐藏层节点,
    # 2个输出层节点(因为是2分类任务,n个分类输出层节点个数就是n)
    CNN_model = Net(input_layer_size, 256, 2)
    loss_func = torch.nn.CrossEntropyLoss() # 损失函数,这里是交叉熵损失,可以换用其他的损失函数
    optimizer = torch.optim.SGD(CNN_model.parameters(), lr=0.01, momentum=0.9)  # 配置网络优化器
    # 训练设备,有GPU就用GPU,没就用CPU
    if (torch.cuda.is_available()):
        print("Using CUDA")
        mgcnn = CNN_model.cuda()
        loss_func = loss_func.cuda()
        x_tensor = x_tensor.cuda()
        y_tensor = y_tensor.cuda()
    # 开始训练
    epochs = 100 # 训练轮数
    fit(CNN_model, loss_func, data_loader, test_data_loader, epochs, optimizer)
    torch.save(CNN_model, './my_net.pth') # 保存模型
相关实践学习
部署Stable Diffusion玩转AI绘画(GPU云服务器)
本实验通过在ECS上从零开始部署Stable Diffusion来进行AI绘画创作,开启AIGC盲盒。
相关文章
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【单点知识】基于实例详解PyTorch中的DataLoader类
【单点知识】基于实例详解PyTorch中的DataLoader类
629 2
|
6月前
|
机器学习/深度学习 算法 PyTorch
【PyTorch实战演练】自调整学习率实例应用(附代码)
【PyTorch实战演练】自调整学习率实例应用(附代码)
235 0
|
6月前
|
PyTorch 算法框架/工具
Pytorch中最大池化层Maxpool的作用说明及实例使用(附代码)
Pytorch中最大池化层Maxpool的作用说明及实例使用(附代码)
570 0
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
基于Pytorch通过实例详细剖析CNN
基于Pytorch通过实例详细剖析CNN
72 1
基于Pytorch通过实例详细剖析CNN
|
6月前
|
机器学习/深度学习 算法 大数据
基于PyTorch对凸函数采用SGD算法优化实例(附源码)
基于PyTorch对凸函数采用SGD算法优化实例(附源码)
105 3
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
【单点知识】基于实例讲解PyTorch中的transforms类
【单点知识】基于实例讲解PyTorch中的transforms类
87 0
|
6月前
|
机器学习/深度学习 数据采集 PyTorch
【单点知识】基于实例讲解PyTorch中的ImageFolder类
【单点知识】基于实例讲解PyTorch中的ImageFolder类
154 0
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
通过实例学习Pytorch加载权重.load_state_dict()与保存权重.save()
通过实例学习Pytorch加载权重.load_state_dict()与保存权重.save()
85 0
|
6月前
|
机器学习/深度学习 PyTorch 算法框架/工具
卷积神经元网络中常用卷积核理解及基于Pytorch的实例应用(附完整代码)
卷积神经元网络中常用卷积核理解及基于Pytorch的实例应用(附完整代码)
127 0
|
6月前
|
机器学习/深度学习 算法 PyTorch
基于Pytorch用GAN生成手写数字实例(附代码)
基于Pytorch用GAN生成手写数字实例(附代码)
156 0