pytorch实战6:手把手教你基于pytorch实现AlexNet

手把手教你基于pytorch实现AlexNet(长文)

前言

​ 最近在看经典的卷积网络架构,打算自己尝试复现一下,在此系列文章中,会参考很多文章,有些已经忘记了出处,所以就不贴链接了,希望大家理解。

​ 完整的代码在最后。

本系列必须的基础

​ python基础知识、CNN原理知识、pytorch基础知识

本系列的目的

​ 一是帮助自己巩固知识点;

​ 二是自己实现一次,可以发现很多之前的不足;

​ 三是希望可以给大家一个参考。

目录结构

1. 前言与参考资料:

​ 之前我写了几篇图像分类算法的复现,但是仅仅复现了网络结构,没有使用数据来尝试训练,因此这篇文章就是来补充之前的内容。

​ 其中的数据集来自于B站的一个up主的GitHub仓库,链接为:

https://github.com/WZMIAOMIAO/deep-learning-for-image-processing

​ 这个up不仅提供了数据集,也提供了相关代码和讲解视频。

但是,我仅仅需要的是数据,因此没有参考他的代码,另外,他的代码写得很好,但是注释不多,虽有讲解视频但我觉得自己实现一次更有意义。

2. 数据集介绍与下载:

数据集下载

方法一:从GitHub中下载,然后还需要自己处理一下。

方法二:从下面的百度云下载:

链接:https://pan.baidu.com/s/12k9fRMRdhxp1fXzoww25rQ 
提取码:6666 

数据集介绍

​ 这个数据集也是来自于网上公开的数据集的子集,是一个花分类的数据集,总共有5个类别,分别为daisy(雏菊)、dandelion(蒲公英)、rose(玫瑰)、sunflower(向日葵)、tulip(郁金香)

​ 从百度网盘获取的数据集,分为两个文件夹,一个为train、一个为test,train中每个类别都有200张图片,共1000张图片;test中每个类别100张图片,共500张图片。

在这里插入图片描述

3. AlexNet模型构建:

​ 这一步直接可以参考我前面的文章,链接为:

https://blog.csdn.net/weixin_46676835/article/details/128730161

​ 其实现的代码我粘贴过来:

# 创建AlexNet模型 227*227
class My_AlexNet(nn.Module):
    def __init__(self):
        super(My_AlexNet, self).__init__()
        # 特征提取
        self.features = nn.Sequential(
            # 输入通道数为3,因为图片为彩色,三通道
            # 而输出96、卷积核为11*11,步长为4,是由AlexNet模型决定的,后面的都同理
            nn.Conv2d(in_channels=3,out_channels=96,kernel_size=11,stride=4),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.Conv2d(in_channels=96,out_channels=256,kernel_size=5,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.Conv2d(in_channels=256,out_channels=384,padding=1,kernel_size=3),
            nn.ReLU(),
            nn.Conv2d(in_channels=384,out_channels=384,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2)
        )
        # 全连接层
        self.classifier = nn.Sequential(
            # 全连接的第一层,输入肯定是卷积输出的拉平值,即6*6*256
            # 输出是由AlexNet决定的,为4096
            nn.Linear(in_features=6*6*256,out_features=4096),
            nn.ReLU(),
            # AlexNet采取了DropOut进行正则,防止过拟合
            nn.Dropout(p=0.5),
            nn.Linear(4096,4096),
            nn.ReLU(),
            # 最后一层,输出1000个类别,也是我们所说的softmax层
            nn.Linear(4096,5)
        )

    # 前向算法
    def forward(self,x):
        x = self.features(x)
        # 不要忘记在卷积--全连接的过程中,需要将数据拉平,之所以从1开始拉平,是因为我们
        # 批量训练,传入的x为[batch(每批的个数),x(长),x(宽),x(通道数)],因此拉平需要从第1(索引,相当于2)开始拉平
        # 变为[batch,x*x*x]
        x = torch.flatten(x,1)
        result = self.classifier(x)
        return result

4. Dataset类构建:

​ 这里,我们需要自己实现Dataset类(用来获取数据和标签,配合Dataloader使用)。

目录结构

​ 在介绍如何写代码前,先说明一下我的目录结构:

data	  # 文件夹
	net_train_images   # 下载后解压的数据文件夹
	net_test_images		# 下载后解压的数据文件夹
图像分类	# 文件夹
	AlexNet.py	 # 代码文件

基本框架

​ 首先,根据pytorch基础知识,写出Dataset类的基本框架:

class My_Dataset(Dataset):
    def __init__(self):
        pass
    def __len__(self):
        pass
    def __getitem__(self,idx):
        pass

_init_()填写

​ 我们需要定义两个基本的参数filename,transform

def __init__(self,filename,transform=None):
    self.filename = filename	# 文件路径
    self.transform = transform  # 是否对图片进行变化

​ 而在init方法中,我们需要获取到我们的**图像路径和相应标签,**因此我们定义一个函数来实现该想法:

def __init__(self,filename,transform=None):
    self.filename = filename	# 文件路径
    self.transform = transform  # 是否对图片进行变化
	# 变化之处
    self.image_name,self.label_image = self.operate_file()	

operate_file方法实现

​ 由于我们的图片存在于多个文件夹中,因此**决定了我们的filename参数应该是一个文件夹路径,**在我的目录结构中应该为:

'../data/net_train_images'

​ 因此,可以这么写代码(看注释

def operate_file(self):
    # 获取所有的文件夹路径 '../data/net_train_images'下的文件夹
    dir_list = os.listdir(self.filename)
    # 拼凑出图片完整路径 '../data/net_train_images' + '/' + 'xxx.jpg'
    full_path = [self.filename+'/'+name for name in dir_list]
    # 获取里面的图片名字
    name_list = []
    for i,v in enumerate(full_path):
        temp = os.listdir(v)
        temp_list = [v+'/'+j for j in temp]
        name_list.extend(temp_list)
	# 由于一个文件夹的所有标签都是同一个值,而字符值必须转为数字值,因此我们使用数字0-4代替标签值
    # 将标签每个复制200个
    label_list = []
    temp_list = np.array([0,1,2,3,4],dtype=np.int64) # 用数字代表不同类别
    for j in range(5):
        for i in range(200):
        	label_list.append(temp_list[j])
    return name_list,label_list

​ 这里,我必须解释一下:**为什么np那里需要声明为int64类型?**因为你训练的时候,使用损失函数计算loss(pred,ture_label)那里,必须要求int类型为int64。(这个错误困扰我半个小时)

__len__方法填写

​ 这个简单,直接按照固定套路写即可:

def __len__(self):
    return len(self.image_name)

__getitem__方法填写

​ 实现的思路:打开图片、对图片下采样为227*227、获取标签、是否需要处理、转为tensor对象、返回值。

​ 具体代码为:(看注释

def __getitem__(self,idx):
    # 由路径打开图片
    image = Image.open(self.image_name[idx])
    # 下采样: 因为图片大小不同,需要下采样为227*227
    trans = transforms.RandomResizedCrop(227)
    image = trans(image)
    # 获取标签值
    label = self.label_image[idx]
    # 是否需要处理
    if self.transform:
    	image = self.transform(image)
    # 转为tensor对象
    label = torch.from_numpy(np.array(label))
    return image,label

完整代码

class My_Dataset(Dataset):
    def __init__(self,filename,transform=None):
        self.filename = filename   # 文件路径
        self.transform = transform # 是否对图片进行变化
        self.image_name,self.label_image = self.operate_file()

    def __len__(self):
        return len(self.image_name)

    def __getitem__(self,idx):
        # 由路径打开图片
        image = Image.open(self.image_name[idx])
        # 下采样: 因为图片大小不同,需要下采样为227*227
        trans = transforms.RandomResizedCrop(227)
        image = trans(image)
        # 获取标签值
        label = self.label_image[idx]
        # 是否需要处理
        if self.transform:
            image = self.transform(image)
        # 转为tensor对象
        label = torch.from_numpy(np.array(label))
        return image,label

    def operate_file(self):
        # 获取所有的文件夹路径 '../data/net_train_images'的文件夹
        dir_list = os.listdir(self.filename)
        # 拼凑出图片完整路径 '../data/net_train_images' + '/' + 'xxx.jpg'
        full_path = [self.filename+'/'+name for name in dir_list]
        # 获取里面的图片名字
        name_list = []
        for i,v in enumerate(full_path):
            temp = os.listdir(v)
            temp_list = [v+'/'+j for j in temp]
            name_list.extend(temp_list)
        # 由于一个文件夹的所有标签都是同一个值,而字符值必须转为数字值,因此我们使用数字0-4代替标签值
        label_list = []
        temp_list = np.array([0,1,2,3,4],dtype=np.int64) # 用数字代表不同类别
        # 将标签每个复制200个
        for j in range(5):
            for i in range(200):
                label_list.append(temp_list[j])
        return name_list,label_list

5. 训练过程:

​ 在完成了模型创建、Dataset类构建,就可以开始着手实现训练过程了。

​ 这里,我将训练过程放入了一个名为train的函数中进行。

def train():
	pass

前期准备

​ 首先,创建我们的模型,并将模型放入GPU中:

def train():
    model = My_AlexNet() # 创建模型
    # 将模型放入GPU中
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    model.to(device)

声明,为了简便,后面不会写重复的部分,只会写新多出来的部分。

​ 接着,我们定义损失函数,这里采取分类任务常用的交叉熵损失函数:

# 定义损失函数
loss_func = nn.CrossEntropyLoss()

​ 然后,定义优化器,这里采取Adam优化器:

# 定义优化器
optimizer = optim.Adam(params=model.parameters(),lr=0.0002)

​ 下一步,定义每批训练的数据个数并加载数据:

batch_size = 32     # 批量训练大小
# 加载数据
train_set = My_Dataset('../data/net_train_images',transform=transforms.ToTensor())
train_loader = DataLoader(train_set, batch_size, shuffle=True)

训练中

​ 假设训练20次,并定义一个临时变量loss_temp来存储损失值:

# 训练20次
for i in range(20): 
	loss_temp = 0  # 临时变量

​ 接着,批量批次接收数据:

for i in range(20):
	loss_temp = 0  # 临时变量
	for j,(batch_data,batch_label) in enumerate(train_loader):
        # 之后的代码都在这个循环中

​ 首先,把数据放入GPU中:

# 数据放入GPU中
batch_data,batch_label = batch_data.cuda(),batch_label.cuda()

​ 接着,便是丝滑小连招:

# 梯度清零
optimizer.zero_grad()
# 模型训练
prediction = model(batch_data)
# 损失值
loss = loss_func(prediction,batch_label)
loss_temp += loss.item()
# 反向传播
loss.backward()
# 梯度更新
optimizer.step()

​ 当内层结束循环时,打印一下这次的平均损失值:

# 这里新增的
print('[%d] loss: %.3f' % (i+1,loss_temp/len(train_loader)))

完整代码

# 训练过程
def train():
    batch_size = 32     # 批量训练大小
    model = My_AlexNet() # 创建模型
    # 将模型放入GPU中
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    model.to(device)
    # 定义损失函数
    loss_func = nn.CrossEntropyLoss()
    # 定义优化器
    optimizer = optim.Adam(params=model.parameters(),lr=0.0002)
    # 加载数据
    train_set = My_Dataset('../data/net_train_images',transform=transforms.ToTensor())
    train_loader = DataLoader(train_set, batch_size, shuffle=True)
    # 训练20次
    for i in range(20):
        loss_temp = 0  # 临时变量
        for j,(batch_data,batch_label) in enumerate(train_loader):
            # 数据放入GPU中
            batch_data,batch_label = batch_data.cuda(),batch_label.cuda()
            # 梯度清零
            optimizer.zero_grad()
            # 模型训练
            prediction = model(batch_data)
            # 损失值
            loss = loss_func(prediction,batch_label)
            loss_temp += loss.item()
            # 反向传播
            loss.backward()
            # 梯度更新
            optimizer.step()
            # 每25个批次打印一次损失值
        print('[%d] loss: %.3f' % (i+1,loss_temp/len(train_loader)))

6. 训练中:

​ 尝试运行整个代码,运行结果如下:

[1] loss: 1.587
[2] loss: 1.389
[3] loss: 1.312
[4] loss: 1.303
[5] loss: 1.233
[6] loss: 1.185
[7] loss: 1.165
[8] loss: 1.118
[9] loss: 1.113
[10] loss: 1.097
[11] loss: 1.078
[12] loss: 1.099
[13] loss: 1.037
[14] loss: 0.999
[15] loss: 1.014
[16] loss: 1.010
[17] loss: 0.948
[18] loss: 0.936
[19] loss: 0.945
[20] loss: 0.870

7. 测试代码:

​ 测试代码部分很简单,只是注意我们使用索引值代替类别:

def test(model):
    # 批量数目
    batch_size = 10
    # 预测正确个数
    correct = 0
    # 加载数据
    test_set = My_Dataset_test('../data/net_test_images', transform=transforms.ToTensor())
    test_loader = DataLoader(test_set, batch_size, shuffle=False)
    # 开始
    for batch_data,batch_label in test_loader:
        # 放入GPU中
        batch_data, batch_label = batch_data.cuda(), batch_label.cuda()
        # 预测
        prediction = model(batch_data)
        # 将预测值中最大的索引取出,其对应了不同类别值
        predicted = torch.max(prediction.data, 1)[1]
        # 获取准确个数
        correct += (predicted == batch_label).sum()
    print('准确率: %.2f %%' % (100 * correct / 500)) # 因为总共500个测试数据

​ 另外,还需要改下Dataset中的一点,即构建标签中的200变为100,因此又写了一个类:

class My_Dataset_test(My_Dataset):
    def operate_file(self):
        # 获取所有的文件夹路径
        dir_list = os.listdir(self.filename)
        full_path = [self.filename+'/'+name for name in dir_list]
        # 获取里面的图片名字
        name_list = []
        for i,v in enumerate(full_path):
            temp = os.listdir(v)
            temp_list = [v+'/'+j for j in temp]
            name_list.extend(temp_list)
        # 将标签每个复制一百个
        label_list = []
        temp_list = np.array([0,1,2,3,4],dtype=np.int64) # 用数字代表不同类别
        for j in range(5):
            for i in range(100): # 只修改了这里
                label_list.append(temp_list[j])
        return name_list,label_list

​ 运行的时候,把他放入train函数中,传入模型参数即可。

​ 最后运行的结果为:

[1] loss: 1.595
[2] loss: 1.413
[3] loss: 1.342
[4] loss: 1.231
[5] loss: 1.172
[6] loss: 1.109
[7] loss: 1.146
[8] loss: 1.090
[9] loss: 1.024
[10] loss: 0.977
[11] loss: 0.962
[12] loss: 0.901
[13] loss: 0.950
[14] loss: 0.900
[15] loss: 0.970
[16] loss: 0.881
[17] loss: 0.843
[18] loss: 0.818
[19] loss: 0.784
[20] loss: 0.760
准确率: 64.20 %

8. 分析与总结:

分析与总结

​ 我总结了一下我写代码中遇到的问题与解决方法:

  • 如何构建dataset

    • 这次从头到尾实现dataset类,帮我深入理解了其原理
  • 下采样和上采样方法

    • 由于图片大小不一致,因此需要下采样,这里使用了方法:transforms.RandomResizedCrop(227)

    • 之前我不知道有这个方法,我使用的是下面的方式实现

      # image = image.reshape(1,image.size(0),image.size(1),image.size(2))
      # print('变换前',image.size())
      # image = interpolate(image, size=(227, 227))
      # image = image.reshape(image.size(1),image.size(2),image.size(3))
      # print('变换后', image.size())
      
  • 需要将图像的标签值转为数字值

  • 遇到一个错误

    •   RuntimeError: "nll_loss_forward_reduce_cuda_kernel_2d_index" not implemented for 'Int'
      
    • 这个错误就是我之前提到的,必须把标签的数字值设为int64才可以

  • 损失值一直稳定某个值附近,比如我之前采取SGD作为优化器的时候,就出现了损失值一直在1.610附近徘徊,当时我一直以为是我的代码写错了导致的,后来慢慢排查才发现代码没有错,可能是采取SGD优化器一下就到了收敛值附近,导致损失值一直下不去;也有可能是发生了梯度消失的问题,导致无法优化。

    [1] loss: 1.610
    [2] loss: 1.610
    [3] loss: 1.610
    [4] loss: 1.610
    [5] loss: 1.610
    [6] loss: 1.610
    [7] loss: 1.610
    [8] loss: 1.609
    [9] loss: 1.609
    [10] loss: 1.610
    [11] loss: 1.609
    [12] loss: 1.609
    [13] loss: 1.610
    [14] loss: 1.609
    [15] loss: 1.609
    [16] loss: 1.610
    [17] loss: 1.610
    [18] loss: 1.609
    [19] loss: 1.609
    [20] loss: 1.609
    准确率: 21.80 %
    
  • 为什么准确率比较低?

    • 这个问题,我觉得有几方面的原因(个人分析,不一定正确)。
    • 首先,数据量小,但是模型参数量大而深,容易过拟合导致测试精度低。
    • 另外,参数量大也意味着容易出现梯度消失的问题,导致模型无法持续有效训练。

完整代码

# author: baiCai
# 导入模块
import os
from PIL import Image
import numpy as np
import torch
from torch import nn
from torch.nn.functional import  interpolate
from torch import optim
from torchvision import transforms
from torch.utils.data import Dataset,DataLoader
from torchvision.models import AlexNet

# 创建AlexNet模型 227*227
class My_AlexNet(nn.Module):
    def __init__(self):
        super(My_AlexNet, self).__init__()
        # 特征提取
        self.features = nn.Sequential(
            # 输入通道数为3,因为图片为彩色,三通道
            # 而输出96、卷积核为11*11,步长为4,是由AlexNet模型决定的,后面的都同理
            nn.Conv2d(in_channels=3,out_channels=96,kernel_size=11,stride=4),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.Conv2d(in_channels=96,out_channels=256,kernel_size=5,padding=2),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2),
            nn.Conv2d(in_channels=256,out_channels=384,padding=1,kernel_size=3),
            nn.ReLU(),
            nn.Conv2d(in_channels=384,out_channels=384,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.Conv2d(in_channels=384,out_channels=256,kernel_size=3,padding=1),
            nn.ReLU(),
            nn.MaxPool2d(kernel_size=3,stride=2)
        )
        # 全连接层
        self.classifier = nn.Sequential(
            # 全连接的第一层,输入肯定是卷积输出的拉平值,即6*6*256
            # 输出是由AlexNet决定的,为4096
            nn.Linear(in_features=6*6*256,out_features=4096),
            nn.ReLU(),
            # AlexNet采取了DropOut进行正则,防止过拟合
            nn.Dropout(p=0.5),
            nn.Linear(4096,4096),
            nn.ReLU(),
            # 最后一层,输出1000个类别,也是我们所说的softmax层
            nn.Linear(4096,5)
        )

    # 前向算法
    def forward(self,x):
        x = self.features(x)
        # 不要忘记在卷积--全连接的过程中,需要将数据拉平,之所以从1开始拉平,是因为我们
        # 批量训练,传入的x为[batch(每批的个数),x(长),x(宽),x(通道数)],因此拉平需要从第1(索引,相当于2)开始拉平
        # 变为[batch,x*x*x]
        x = torch.flatten(x,1)
        result = self.classifier(x)
        return result

# AlexNet 要求模型的输入大小为:227*227*3,因此需要下采样——裁剪
class My_Dataset(Dataset):
    def __init__(self,filename,transform=None):
        self.filename = filename   # 文件路径
        self.transform = transform # 是否对图片进行变化
        self.image_name,self.label_image = self.operate_file()

    def __len__(self):
        return len(self.image_name)

    def __getitem__(self,idx):
        # 由路径打开图片
        image = Image.open(self.image_name[idx])
        # 下采样: 因为图片大小不同,需要下采样为227*227
        trans = transforms.RandomResizedCrop(227)
        image = trans(image)
        # 获取标签值
        label = self.label_image[idx]
        # 是否需要处理
        if self.transform:
            image = self.transform(image)
            # image = image.reshape(1,image.size(0),image.size(1),image.size(2))
            # print('变换前',image.size())
            # image = interpolate(image, size=(227, 227))
            # image = image.reshape(image.size(1),image.size(2),image.size(3))
            # print('变换后', image.size())
        # 转为tensor对象
        label = torch.from_numpy(np.array(label))
        return image,label

    def operate_file(self):
        # 获取所有的文件夹路径 '../data/net_train_images'的文件夹
        dir_list = os.listdir(self.filename)
        # 拼凑出图片完整路径 '../data/net_train_images' + '/' + 'xxx.jpg'
        full_path = [self.filename+'/'+name for name in dir_list]
        # 获取里面的图片名字
        name_list = []
        for i,v in enumerate(full_path):
            temp = os.listdir(v)
            temp_list = [v+'/'+j for j in temp]
            name_list.extend(temp_list)
        # 由于一个文件夹的所有标签都是同一个值,而字符值必须转为数字值,因此我们使用数字0-4代替标签值
        label_list = []
        temp_list = np.array([0,1,2,3,4],dtype=np.int64) # 用数字代表不同类别
        # 将标签每个复制200个
        for j in range(5):
            for i in range(200):
                label_list.append(temp_list[j])
        return name_list,label_list

class My_Dataset_test(My_Dataset):
    def operate_file(self):
        # 获取所有的文件夹路径
        dir_list = os.listdir(self.filename)
        full_path = [self.filename+'/'+name for name in dir_list]
        # 获取里面的图片名字
        name_list = []
        for i,v in enumerate(full_path):
            temp = os.listdir(v)
            temp_list = [v+'/'+j for j in temp]
            name_list.extend(temp_list)
        # 将标签每个复制一百个
        label_list = []
        temp_list = np.array([0,1,2,3,4],dtype=np.int64) # 用数字代表不同类别
        for j in range(5):
            for i in range(100): # 只修改了这里
                label_list.append(temp_list[j])
        return name_list,label_list

# 训练过程
def train():
    batch_size = 32     # 批量训练大小
    model = My_AlexNet() # 创建模型
    # 将模型放入GPU中
    device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu")
    model.to(device)
    # 定义损失函数
    loss_func = nn.CrossEntropyLoss()
    # 定义优化器
    optimizer = optim.Adam(params=model.parameters(),lr=0.0002)
    # 加载数据
    train_set = My_Dataset('../data/net_train_images',transform=transforms.ToTensor())
    train_loader = DataLoader(train_set, batch_size, shuffle=True)
    # 训练20次
    for i in range(20):
        loss_temp = 0  # 临时变量
        for j,(batch_data,batch_label) in enumerate(train_loader):
            # 数据放入GPU中
            batch_data,batch_label = batch_data.cuda(),batch_label.cuda()
            # 梯度清零
            optimizer.zero_grad()
            # 模型训练
            prediction = model(batch_data)
            # 损失值
            loss = loss_func(prediction,batch_label)
            loss_temp += loss.item()
            # 反向传播
            loss.backward()
            # 梯度更新
            optimizer.step()
            # 每25个批次打印一次损失值
        print('[%d] loss: %.3f' % (i+1,loss_temp/len(train_loader)))
    test(model)

def test(model):
    # 批量数目
    batch_size = 10
    # 预测正确个数
    correct = 0
    # 加载数据
    test_set = My_Dataset_test('../data/net_test_images', transform=transforms.ToTensor())
    test_loader = DataLoader(test_set, batch_size, shuffle=False)
    # 开始
    for batch_data,batch_label in test_loader:
        # 放入GPU中
        batch_data, batch_label = batch_data.cuda(), batch_label.cuda()
        # 预测
        prediction = model(batch_data)
        # 将预测值中最大的索引取出,其对应了不同类别值
        predicted = torch.max(prediction.data, 1)[1]
        # 获取准确个数
        correct += (predicted == batch_label).sum()
    print('准确率: %.2f %%' % (100 * correct / 500)) # 因为总共500个测试数据


if __name__ == '__main__':
    train()
  • 10
    点赞
  • 70
    收藏
    觉得还不错? 一键收藏
  • 7
    评论
PyTorch是一个用于深度学习的开源Python库,它提供了丰富的工具和函数,可以简化神经网络模型的实现。Transformers是一种用于自然语言处理的深度学习模型,其基本方法是通过自注意力机制来实现文本序列的编码和解码。下面将手把手你如何使用PyTorch实现Transformers。 1. 首先,安装PyTorch库。可以通过pip命令来安装:`pip install torch`。 2. 导入必要的库。在代码的开头,导入PyTorch和Transformers相关的库: ``` import torch from transformers import BertModel, BertTokenizer ``` 3. 加载预训练的Transformers模型和分词器。Transformers库提供了一些预训练的模型,可以从Hugging Face的模型库中下载。我们使用Bert模型作为例子: ``` model_name = 'bert-base-uncased' model = BertModel.from_pretrained(model_name) tokenizer = BertTokenizer.from_pretrained(model_name) ``` 4. 输入编码。将文本输入编码成模型所需的格式。使用分词器对文本进行分词,并将分词后的结果转化为模型所需的编码格式: ``` text = "I love PyTorch" tokens = tokenizer.tokenize(text) input_ids = tokenizer.convert_tokens_to_ids(tokens) input_tensor = torch.tensor([input_ids]) ``` 5. 模型前向计算。将输入数据传入模型进行前向计算: ``` model_output = model(input_tensor) ``` 6. 获取特征表示。从模型输出中获取特征表示。对于Bert模型,可以获取词嵌入和每个词的隐藏状态: ``` embeddings = model_output[0] # 词嵌入 hidden_states = model_output[2] # 每个词的隐藏状态 ``` 7. 解码输出。根据任务需求,对模型的输出进行解码。例如,可以使用BertPooler层获取整个句子的语义表示: ``` pooler_output = model.pooler(hidden_states[-1]) # BertPooler层 ``` 以上就是用PyTorch实现Transformers的基本步骤。根据具体任务的不同,可以对模型进行进一步的调整和优化。希望这个手把手程能够帮到你!

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值