Pytorch中torch.save时产生Unknown error:-1的错误解析

最近在用Pytorch的时候,出现了一个错误,error traceback如下:

Traceback (most recent call last):
File "main-train.py", line 250, in main()
File "main-train.py", line 232, in main
m.state_dict(), '../exp/{}/{}/model_{}.pth'.format(opt.dataset, opt.expID, opt.epoch))
File "/usr/local/lib/python3.5/dist-packages/torch/serialization.py", line 135, in save
return _with_file_like(f, "wb", lambda f: _save(obj, f, pickle_module, pickle_protocol))
File "/usr/local/lib/python3.5/dist-packages/torch/serialization.py", line 117, in _with_file_like
return body(f)
File "/usr/local/lib/python3.5/dist-packages/torch/serialization.py", line 135, in 
return _with_file_like(f, "wb", lambda f: _save(obj, f, pickle_module, pickle_protocol))
File "/usr/local/lib/python3.5/dist-packages/torch/serialization.py", line 204, in _save
serialized_storages[key]._write_file(f)
RuntimeError: Unknown error -1

如这个错误栈所示,这是在调用torch.save保存模型的时候发生的,具体的错误发生位置在torch/serialization.py中,而且在Pytorch 0.3.1Pytorch 0.4我都遇到了这个问题,下面贴出serialization.py对应函数的代码(从Pytorch0.3.0中文文档中复制黏贴,对于0.3.10.4版本,代码类似):

def save(obj, f, pickle_module=pickle, pickle_protocol=DEFAULT_PROTOCOL):
    """将一个对象保存到一个磁盘文件中.

    另见: :ref:`recommend-saving-models`

    参数:
        obj: 要保存的对象
        f: 类文件对象 (必须实现返回文件描述符的 fileno 方法) 或包含文件名的字符串
        pickle_module: 用于 pickling 元数据和对象的模块
        pickle_protocol: 可以指定来覆盖默认协议
    """
    return _with_file_like(f, "wb", lambda f: _save(obj, f, pickle_module, pickle_protocol))

def _save(obj, f, pickle_module, pickle_protocol):
    import torch.nn as nn
    serialized_container_types = {}
    serialized_storages = {}

    def persistent_id(obj):
        # FIXME: the docs say that persistent_id should only return a string
        # but torch store returns tuples. This works only in the binary protocol
        # see
        # https://docs.python.org/2/library/pickle.html#pickling-and-unpickling-external-objects
        # https://github.com/python/cpython/blob/master/Lib/pickle.py#L527-L537
        if isinstance(obj, type) and issubclass(obj, nn.Module):
            if obj in serialized_container_types:
                return None
            serialized_container_types[obj] = True
            source_file = source = None
            try:
                source_file = inspect.getsourcefile(obj)
                source = inspect.getsource(obj)
            except Exception:  # saving the source is optional, so we can ignore any errors
                warnings.warn("Couldn't retrieve source code for container of "
                              "type " + obj.__name__ + ". It won't be checked "
                              "for correctness upon loading.")
            return ('module', obj, source_file, source)
        elif torch.is_storage(obj):
            storage_type = normalize_storage_type(type(obj))
            root, offset = obj._root_storage()
            root_key = str(root._cdata)
            location = location_tag(obj)
            serialized_storages[root_key] = root
            is_view = obj._cdata != root._cdata
            if is_view:
                view_metadata = (str(obj._cdata), offset, obj.size())
            else:
                view_metadata = None

            return ('storage',
                    storage_type,
                    root_key,
                    location,
                    root.size(),
                    view_metadata)

        return None

    sys_info = dict(
        protocol_version=PROTOCOL_VERSION,
        little_endian=sys.byteorder == 'little',
        type_sizes=dict(
            short=SHORT_SIZE,
            int=INT_SIZE,
            long=LONG_SIZE,
        ),
    )

    pickle_module.dump(MAGIC_NUMBER, f, protocol=pickle_protocol)
    pickle_module.dump(PROTOCOL_VERSION, f, protocol=pickle_protocol)
    pickle_module.dump(sys_info, f, protocol=pickle_protocol)
    pickler = pickle_module.Pickler(f, protocol=pickle_protocol)
    pickler.persistent_id = persistent_id
    pickler.dump(obj)

    serialized_storage_keys = sorted(serialized_storages.keys())
    pickle_module.dump(serialized_storage_keys, f, protocol=pickle_protocol)
    f.flush()
    for key in serialized_storage_keys:
        serialized_storages[key]._write_file(f)

对于这个错误,可能有多个原因,两类较为常见的是:

  1. 保存模型时,目标目录下的磁盘空间不够了,类似的issue已经被多人报告过(如Pytorch Forum上的讨论),对于这种情况的解决比较简单,把模型保存到其他存储空间的路径就可以了。
  2. 因为Pytorch目前版本中一个较为隐蔽的BUG,相关的说明见Github上的issue#8477),原因较为复杂,issue的报告人给出了相关的推断:

I added some code in the source code to print the error and signal, then reproduced and got the bold lines.Seems like save operation happened right after validation finished, exit of worker subprocesses caused the SIGCHLD, then interrupted "write" system call.

简单来说,就是因为在一个epoch的训练结束后的validation结束时,对应的worker子进程会结束,抛出来一个SIGCHLD信号,然后这个信号有时候会调动父进程把当前进行“write”操作的动作终止掉,也就是终止了保存模型时对硬盘写入的操作。

对于这种情况,当然可以通过比较复杂的手段来解决,但是最简单的方法就是在torch.save之前加入一定的等待时间,避免对应的SIGCHLD操作造成影响,比如插入:

import time
time.sleep(10)

非常不幸的,上述两种情况我都遇到过,第一种情况很快解决了,第二种困扰了我很久。总的来说,这是一个Pytorch当前版本的BUG,而且在产生错误的时候没有给出友好的错误信息,前述两种情况对应的产生原因实际上是不一样的,但是都没有预先设置的友好的错误处理机制处理,才产生了“unkown error”这样的信息。所以,这个报错之下,也很有可能会有别的错误原因存在,也欢迎大家的分享。

PS. Pytorch的团队已经注意到了这个问题,并且将这个issue的处理添加到了TODO中,预计在之后的版本会得到处理。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343

推荐阅读更多精彩内容

  • rljs by sennchi Timeline of History Part One The Cognitiv...
    sennchi阅读 7,285评论 0 10
  • 每过一段时间,总会有一个python库被开发出来,改变深度学习领域。而PyTorch就是这样一个库。 在过去的几周...
    AiTechYun阅读 3,996评论 0 4
  • 官方所有教程的地址:pytorch.org/tutorials 以下是基于实例来入门pytorch Learnin...
    MiracleJQ阅读 1,822评论 0 4
  • 儿子会编故事了 一只小船在路边晃晃悠悠的,突然掉到很深的河里,很深很深,还碰到了大鲨鱼,妈妈你说谁可怜,我说谁都不...
    熙熙0920阅读 174评论 0 0
  • YEP丁日阅读 178评论 0 0