还可以更快更强 | huggingface加载本地模型


分析问题

问题的起源

事情起因是这样的,我们要使用huggingface,但是日常因为联网问题无法加载模型。因为是服务器集群,搭梯子让我们在docker里弄,所以像我这种懒人,docker?算了,我还是直接手动下载吧,具体看这:服务器huggingface联网通用方案

  • 问题:不能联网下模型,不想搭梯子

  • 解决:缓存模型

但是我是个懒人,我解决的方法只直接在系统默认缓存位置的.cache里缓存文件。

这会带来另一个问题。模型加载过程中会有很大一部分在加载模型。

因为如果你没修改过from_pretrainedforce_download (bool, optional, defaults to False),那么他加载模型的逻辑是这样的:

rust 复制代码
需要加载模型的时候:
去缓存里找-->找不到-->去huggingface下载-->下载不下来-->去缓存里找-->没找到-->报错
    |                                                   |
    -->找到-->加载模型                           -->找到-->加载模型

我的实验用到4个预训练模型,以及n个huggingface的评价指标。

这个过程会耗费大量的时间。

耗费大量时间,根本无所谓,毕竟我懒,根本不想改代码。

但是。问题来了。在我6卡V100跑了两个多周之后,师兄跑来问我是不是实验卡了。

因为他采样时候是这样的,只占一捏捏缓存,GPU是不用的。

为了不挨骂,我决定改一下代码。


修改

评价指标

先说评价指标:

PY 复制代码
def compute_perplexity(all_texts_list, model_id='gpt2-large'):
    torch.cuda.empty_cache() 
    perplexity = load("perplexity", module_type="metric")
    results = perplexity.compute(predictions=all_texts_list, model_id=model_id, device='cuda')
    return results['mean_perplexity']

我这段代码里需要加载评价指标perplexity加载模型gpt2-large

现看加载评价指标的load:

这里写的:

a local path to processing script or the directory containing the script (if the script has the same name as the directory),e.g. './metrics/rouge' or './metrics/rouge/rouge.py'

需要你把评价指标外嵌套一个同名的文件夹。所以文件应该如下放置。

为了确保准确,我这里传入绝对位置,需要借助os

py 复制代码
# 获得当前文件夹的目录
import os
cur_dir = os.path.split(__file__)[0]

os.path.split(__file__): __file__ 是Python中的一个内置变量,它指向当前脚本文件的路径。os.path.split() 函数将这个路径分为两部分,第一部分是文件所在的目录,第二部分是文件名。例如,如果 __file__ 的值是'/path/to/script.py',那么 os.path.split(__file__) 将返回 ('/path/to', 'script.py')

cur_dir = os.path.split(__file__)[0]: 这一行代码获取了当前脚本文件所在的目录,即 '/path/to'。它将目录部分提取出来并存储在变量 cur_dir 中。

f"{cur_dir}/perplexity"即可获得我当前目录存的perplexity。

模型

因为perplexity需要用到预训练模型,我们可以看到我们传入的model_id是模型名,点进这个计算函数看一下。

可以看到传入的model_id直接在这里进行了模型加载。

from_pretrained实现代码注释这样写。

A string, the model id of a predefined tokenizer hosted inside a model repo on huggingface.co. Valid model ids can be located at the root-level, like bert-base-uncased, or namespaced under auser or organization name, like dbmdz/bert-base-german-cased.

传入本地文件夹包含模型文件即可。

所以我们只需要将缓存中的模型及其配置新建个文件夹放进去即可。

看一下文件夹嵌套就知道为什么传入绝对地址了。

compute_perplexity是evaluation.py的函数,但是这个函数引用了同目录下的perplexity/perplexity.py,但是这个perplexity.py要load上上级文件夹下的模型。为了防止混乱,我们还是使用os.path获取位置比较方便。

py 复制代码
import os

model_id = "gpt2-large"
cur_dir = os.path.split(__file__)[0]
model_dir = '/'.join(cur_dir.split('/')[:-1])
print(f"{model_dir}/assist_model/{model_id}")

这段代码用于获取当前脚本文件所在目录的上级目录(parent directory)的路径,通常用于构建文件路径或定位相关资源文件。

cur_dir.split('/'): 这一行代码使用斜杠 / 分割 cur_dir 中的路径字符串,将其拆分成一个列表。例如,如果 cur_dir 的值是 '/path/to',那么 cur_dir.split('/') 将返回 ['', 'path', 'to']

[:-1]: 这是一个切片操作,它用于获取列表中除了最后一个元素之外的所有元素。在这里,[:-1] 表示获取拆分后列表中的所有元素,除了最后一个元素 'to'

'/':这是字符串,用于将列表中的元素连接起来,形成一个新的路径字符串。

最终,model_dir 的值将是当前脚本文件所在的目录的上级目录的路径,具体取决于当前脚本文件的位置和文件系统的路径分隔符。

这样我们就能在evaluation.py获取到上级文件夹的模型。

修改之后的代码如下,我们就可以全部从本地文件夹直接加载了。

py 复制代码
import os

cur_dir = os.path.split(__file__)[0]
model_dir = '/'.join(cur_dir.split('/')[:-1])

def compute_perplexity(all_texts_list, model_id='gpt2-large'):
    torch.cuda.empty_cache()
    perplexity = load(f"{cur_dir}/perplexity", module_type="metric")
    model_id = f"{model_dir}/assist_model/{model_id}"
    results = perplexity.compute(predictions=all_texts_list, model_id=model_id, device='cuda')
    return results['mean_perplexity']

总结

  1. 找到loadfrom_pretrained

  2. 把模型丢个文件夹里

  3. os.path传入绝对路径


其他

问题1

提问:

为什么要在项目里搞个本地文件夹加载模型和评价指标?直接load的时候从本地缓存加载不就行了。

回答:

我都要load本地地址了,我为什么不搞个好load的,还要搞那一长串缓存地址?

C:\Users\ann\.cache\huggingface\hub\models--gpt2-large\snapshots\97935fc1a406f447320c3db70fe9e9875dca2595
D:\ld4_off\model\gpt2-large

1和2我选2.

问题2

提问: 嫌弃默认的.cache,为什么不改个缓存地址?

回答: 确实,

py 复制代码
from transformers import set_cache_dir, AutoModel

# 设置全局的缓存目录
set_cache_dir('/path/to/cache/directory')

# 使用from_pretrained函数加载模型(确保引用全局缓存目录)
model = AutoModel.from_pretrained('bert-base-uncased',cache_dir='/path/to/model/cache')

# 此时模型将从缓存加载,如果缓存不存在,它将尝试从缓存加载,而不重新下载

这样可以修改缓存位置,但是,他好像还是缓存啊......,还是从缓存里读的那个逻辑,还是要走他那个从cache加载的逻辑,不如直接load本地模型吧。我个人感觉是直接加载本地模型更快。

信我,速改,改完以后极其丝滑:

相关推荐
憨憨小白几秒前
函数的高级应用
开发语言·python·青少年编程·少儿编程
CV-King8 分钟前
计算机视觉硬件知识点整理(三):镜头
图像处理·人工智能·python·opencv·计算机视觉
惟长堤一痕16 分钟前
医学数据分析实训 项目三 关联规则分析作业--在线购物车分析--痹症方剂用药规律分析
python·数据分析
eeee~~20 分钟前
GeoPandas在地理空间数据分析中的应用
python·jupyter·信息可视化·数据分析·geopandas库
重生之我要进大厂20 分钟前
LeetCode 876
java·开发语言·数据结构·算法·leetcode
Amo Xiang36 分钟前
Python 常用模块(四):shutil模块
开发语言·python
Filotimo_1 小时前
【自然语言处理】实验三:新冠病毒的FAQ问答系统
人工智能·经验分享·笔记·python·学习·自然语言处理·pycharm
KBDYD10101 小时前
C语言--结构体变量和数组的定义、初始化、赋值
c语言·开发语言·数据结构·算法
计算机学姐1 小时前
基于python+django+vue的影视推荐系统
开发语言·vue.js·后端·python·mysql·django·intellij-idea
Crossoads1 小时前
【数据结构】排序算法---桶排序
c语言·开发语言·数据结构·算法·排序算法