利用Docker容器部署GLIP项目

利用Docker容器部署GLIP项目

GLIP模型结构

下载文件

下载包括把东西下载下来+组织成要求的格式+放到正确的位置。

项目代码

项目代码放置在GitHub仓库,下载代码压缩包至本地。

数据集

数据集构建可以参考官方提供的数据集组织页面

针对预训练任务,官方提供了3种数据集,我选择使用规模最小的Flickr30k数据集进行预训练。

  1. 首先,从官网(实际用的是csdn搜索到的国内下载链接)下载Flickr30k图像数据集flickr30k-images,并从GLIP的Github仓库提供的注释文件地址下载注释文件mdetr_annotations

  2. 其次,将图像数据集flickr30k-images依据注释文件划分为训练集、测试集和验证集。

    最初按照官方提供的数据集组织页面组织数据格式,没有进行数据集划分步骤。

    但在运行项目过程种发现:paths_catalog.py文件指示Flickr30k数据集要划分为训练集、测试集和验证集才能进行训练。

    于是这里先划分数据集,划分数据集的工具代码放置在本地D:\04Code\GLIP-utils\splitFlickrDataset.py

    划分结束后,最终得到的图像分为训练集29783张,测试集999张,验证集1000张。

注意事项:

直接从官网/csdn链接下载的Flickr30k数据集的文件夹名称为flickr30k-images,而在paths_catalog.py文件中定义的数据集的文件名称为flickr30k_images。前者中间是短横线,而后者中间是下划线,注意修改为下划线flickr30k_images

针对评估任务,

配置文件及预训练权重

模型的训练和评估过程均会用到相互对应的配置文件(.yaml)和预训练权重文件(.pth),因服务器无法连接外网,所以二者都需要提前下载至本地,然后再上传至服务器。

本项目需要下载的这种类型的文件可以分为两种:一种是GLIP模型的配置文件及预训练权重文件;另一种是由于GLIP模型结构中包含基于Bert的文本编码器,而该文本编码器需要一些预训练的相关文件。因此,针对这两类文件,都需要进行提前下载。

  1. GLIP模型的配置文件及预训练权重文件

    关键:配置文件(.yaml)和预训练权重文件(.pth)要相互对应,具体可参考GitHub仓库Model Zoo表格。

    我选择了其中效果最差、文件大小最小的配置文件(.yaml)和预训练权重文件(.pth),并将其分别组织到目录configs/pretrain和MODEL中。

    为什么组织到这两个目录呢?

    参考GitHub仓库提供的预训练代码(其中涉及到使用的配置文件的位置)预训练权重文件下载位置这两个提示,可以决定这两类文件具体放置到什么位置。

  2. GLIP基于Bert的文本编码器所需的配置文件config.json

    我是怎么知道需要config.json这个文件的呢?

    在代码运行过程中,出现以下错误:

    MaxRetryError("HTTPSConnectionPool(host='huggingface.co', port=443): Max retries exceeded with url: /bert-base-uncased/resolve/main/config.json (Caused by ConnectTimeoutError('Connection to huggingface.co timed out. ), '(Request ID: 7b33f5be-46a9-40b5-a198-d5ff7ef25c7c)')' thrown while requesting HEAD https://huggingface.co/bert-base-uncased/resolve/main/config.json

    ===似乎是说服务器访问huggingface官网连接超时,导致无法下载一个config.json文件。

    然后看具体的报错信息:

    Traceback (most recent call last): File "tools/train_net.py", line 260, in main() File "tools/train_net.py", line 256, in main use_tensorboard=args.use_tensorboard) File "tools/train_net.py", line 37, in train model = build_detection_model(cfg) File "/workspace/maskrcnn_benchmark/modeling/detector/init.py", line 11, in build_detection_model return meta_arch(cfg) File "/workspace/maskrcnn_benchmark/modeling/detector/generalized_vl_rcnn.py", line 96, in init self.language_backbone = build_language_backbone(cfg) File "/workspace/maskrcnn_benchmark/modeling/language_backbone/backbone.py", line 45, in build_backbone return registry.LANGUAGE_BACKBONEScfg.MODEL.LANGUAGE_BACKBONE.MODEL_TYPE File "/workspace/maskrcnn_benchmark/modeling/language_backbone/backbone.py", line 14, in build_bert_backbone body = bert_model.BertEncoder(cfg) File "/workspace/maskrcnn_benchmark/modeling/language_backbone/bert_model.py", line 18, in init config = BertConfig.from_pretrained(self.bert_name)

    ===到这里为止,似乎是说language_backbone加载出现问题,且项目用的是基于Bert的backbone

    File "/opt/conda/lib/python3.7/site-packages/transformers/configuration_utils.py", line 547, in from_pretrained config_dict, kwargs = cls.get_config_dict(pretrained_model_name_or_path, kwargs) File "/opt/conda/lib/python3.7/site-packages/transformers/configuration_utils.py", line 574, in get_config_dict config_dict, kwargs = cls._get_config_dict(pretrained_model_name_or_path, kwargs) File "/opt/conda/lib/python3.7/site-packages/transformers/configuration_utils.py", line 641, in _get_config_dict _commit_hash=commit_hash, File "/opt/conda/lib/python3.7/site-packages/transformers/utils/hub.py", line 453, in cached_file f"We couldn't connect to '{HUGGINGFACE_CO_RESOLVE_ENDPOINT}' to load this file, couldn't find it in the"

    OSError: We couldn't connect to 'https://huggingface.co' to load this file, couldn't find it in the cached files and it looks like bert-base-uncased is not the path to a directory containing a file named config.json.

    ===总之就是在说:我们需要从huggingface官网下载这个config.json文件到本地

    Checkout your internet connection or see how to run the library in offline mode at 'https://huggingface.co/docs/transformers/installation#offline-mode'.

    注意事项:

    从huggingface官网下载到了config.json文件后,又该把它放在哪里呢?

    一开始我随便新建了一个文件夹xxx/bert-base-uncased放置该文件,结果项目运行时一直无法去这个目录中找到该文件。

    最终尝试后直接将该文件放置在bert-base-uncased文件夹下,项目运行时就可以在本地找到这个文件夹

    Bert配置文件放置位置

假设我们已经把docker安装好了(如果还没有安装docker可以参考服务器端使用docker部署项目),现在继续搭建docker容器。

上传服务器

在本地下载好上述代码/数据集/配置文件/预训练权重文件,并按照要求格式组织好结构之后,将其上传至Linux服务器端(上传步骤可以参考vscode连接linux服务器_上传代码至服务器/上传数据集),接下来的所有操作就是在服务器端进行的了。

构建镜像

Dockerfile

首先cd到项目所在文件夹GLIP-main,然后创建Dockerfile文件。

文件内容为

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
# Choose the base image according to your server's GPU

# For newer GPUs:
FROM pytorch/pytorch:1.9.1-cuda11.1-cudnn8-devel

# Install additional dependencies
RUN pip install einops shapely timm yacs tensorboardX ftfy prettytable pymongo transformers -i https://pypi.tuna.tsinghua.edu.cn/simple

# Copy your project files into the Docker container
COPY . /workspace

# Set the working directory to /workspace
WORKDIR /workspace

# Run the project setup script
RUN python setup.py build develop --user

# 运行上述代码发现缺少以下包,所以这里添加安装这些包的代码
RUN pip install pycocotools scipy opencv-python-headless -i https://pypi.tuna.tsinghua.edu.cn/simple

注意事项:

  1. 这里在最开始下载docker镜像时踩了大坑:原本下载的是GLIP的Github仓库推荐的两种镜像
官方推荐docker镜像

结果经过反复测试(真的是反复测试,,不断质疑是不是自己哪个小细节没注意到才导致安装失败),以及查看Issues,最终才确定GLIP项目支持的pytorch版本必须大于1.9.1且小于1.11.0;而官方仓库推荐的2个docker镜像中pytorch的版本都是1.9.0(真的好气喔。。我辣么相信官方。。甚至怀疑自己了。。不靠谱·官方),最终我选择了Dockerhub中的这一镜像pytorch/pytorch:1.9.1-cuda11.1-cudnn8-devel

  1. 在Dockerfile文件中有一行用于"运行项目安装脚本"的代码RUN python setup.py build develop --user,在这里构建镜像时并不会出现什么问题。

    但是,在后期开启训练时出现错误RuntimeError: Not compiled with GPU support,似乎跟它有关。

    因为解决方案如下:

    1. 首先删除项目文件夹下的build目录
    2. 然后重新运行python setup.py build develop --user
    3. 然后开启训练就没问题

    这可能意味着在创建Dockerfile文件时并不需要加这一行代码RUN python setup.py build develop --user,等后期开启训练前再提前运行这句代码就好了

构建镜像

1
2
# 注意这里还是cd到项目文件夹下,因为这句代码的意思是“基于该目录构建镜像”
docker build -t my_glip_image .

开启容器

分配共享内存

为什么在开启容器前需要为docker容器分配共享内存?因为我一开始没分配导致程序报错了。

错误信息:DataLoader worker (pid 53617) is killed by signal: Bus error. It is possible that dataloader's workers are out of shared memory. Please try to raise your shared memory limit.

错误原因:由于在docker镜像中默认限制了共享内存,然而数据处理时pytorch则需要使用共享内存,这就导致了在运行多线程时会将超出限制的DataLoader直接kill掉。

解决方案:在开启容器前为容器分配足够多的共享内存,参考https://zhuanlan.zhihu.com/p/143914966

首先要查看宿主机系统可以为容器提供多少可用的内存

1
2
3
4
#查看系统的总内存
free -h
#查看可分配的总共享内存
df -h /dev/shm
查看可分配共享内存

开启容器

1
docker run -it --gpus all --shm-size 48G --name my_glip_container my_glip_image  /bin/bash 

到目前为止,我们都只是在Linux服务器端运行代码,在开启容器后,接下来我想直接操纵docker容器内的代码和数据。

可以通过vscode直接连接开启的远程docker容器,连接成功后,就可以通过vscode直接操控容器中的文件及目录。

这一过程需要借助vscode的docker插件、并赋予插件相应的权重才能实现。

具体过程如下:

  1. 首先在命令行运行下述命令,为docker插件设置权限,这样docker插件才能检测到开启的容器(即下图左侧的内容) sudo chmod 666 /var/run/docker.sock
  2. 然后按照下图操作
vscode连接docker容器

训练

开始训练之前首先需要修改配置文件中的相关信息,如预训练权重文件、batch_size、数据集的名称等

修改配置文件

预训练权重

选择和配置文件(.yaml)匹配的预训练权重(.pth)【Model Zoo】

数据集

为什么要更改数据集?

因为我们用的不是配置文件中默认的object365_dt_train,而是flickr30k数据集。

怎么更改数据集?

  1. 首先,在当前使用的配置文件(即开启训练的代码--config-file对应的参数值)中找到默认的训练数据集的名称object365_dt_train
  2. 然后,在项目中全局搜索object365_dt_train,找到定义该名称的文件位置paths_catalog.py
  3. 然后,在paths_catalog.py中搜索flickr30k,找到flickr30k数据集对应的训练数据集及其名称flickr30k_train
  4. 最后,修改配置文件中训练数据集的名称,由object365_dt_train修改为flickr30k_train

batch_size

主要是因为显存不够,将训练时batch_size修改为2,测试时batch_size修改为1

一开始无论怎么修改batch都无济于事(我把训练和测试时的batch_size都改为1了项目也运行不起来)。

错误信息:

RuntimeError: DataLoader worker (pid 53617) is killed by signal: Bus error. It is possible that dataloader's workers are out of shared memory. Please try to raise your shared memory limit.

错误原因:

docker容器设置有问题,这就是前面在启动容器时要设置共享内存的原因

参考:https://zhuanlan.zhihu.com/p/143914966

开启训练

1
python tools/train_net.py --config-file configs/pretrain/glip_A_Swin_T_O365.yaml --skip-test --use-tensorboard --override_output_dir ./output_dir

评估

1
2
3
4
5
python tools/test_grounding_net.py \
--config-file configs/pretrain/glip_A_Swin_T_O365.yaml \
--task_config configs/flickr/test.yaml,configs/flickr/val.yaml \
--weight {model_checkpoint} \
OUTPUT_DIR output/evaluation/flickr30k TEST.IMS_PER_BATCH 1 SOLVER.IMS_PER_BATCH 1 TEST.MDETR_STYLE_AGGREGATE_CLASS_NUM 100 TEST.EVAL_TASK grounding MODEL.DYHEAD.FUSE_CONFIG.MLM_LOSS False

未完成

怎么将docker容器中的代码同步至github?