0%

本来,我以为这是一个不太需要关注的问题,之前也遇到过几次了,但是都是搜索引擎一搜然后解决了就没管了.

然后今天在写一个包的过程中又遇到了,又坑了我半天时间,而且搜索引擎找到的解释也大都模凌两可(包括Google),这让我深深的觉得自己离理解这个bug还有点距离,故要记录一下.感觉不搞清楚一点以后还会被坑.

状况

我觉这里的状况还有几个层级,但是导致的结果都是[你的包不能用啦!你走错路啦!]
(因为原来会把这个问题想得很简单,找到一个方案之后,感觉自己似乎已经解决了,但还是报错,就会一直盯着看直到怀疑人生)

目前主要有3点,及解决方式.

遇到的3种情况

  • main‘ is not a package
  • Unresolved reference
  • ModuleNotFoundError: No module named ‘dir1’

接下来我要比较详细的记录一下几个问题的过程及处理步骤,主要是深化自己的理解,也希望会对遇到同样问题的同学能有帮助.
当然我的理解可能也不是基础理解,可能会有错漏,所以也请谨慎参考,欢迎拍砖交流.

项目结构

1
2
3
4
5
6
7
testmodule
├── dir1
│   ├── dir1_1_f.py
│   └── dir1_2_f.py
├── dir2
│   └── dir2_f.py
└── test_main.py

整个目录放在testmodule的根目录下,有一个主测试文件test_main.py和两个子文件夹,内容分别如下:
testmodule/test_main.py

1
2
3
4
5
6
7
8
9
from dir1.dir1_1_f import dir1_1_fun
from dir2.dir2_f import dir2_fun

def test_main():
dir1_1_fun()
dir2_fun()

if __name__ == '__main__':
test_main()

testmodule/dir1/dir1_1_f.py

1
2
def dir1_1_fun():
print('dir1_1_fun')

testmodule/dir1/dir1_2_f.py

1
2
3
4
5
6
7
from dir1_1_f import dir1_1_fun

def dir1_2_fun():
print('dir1_2_fun')

if __name__ == '__main__':
dir1_1_fun()

testmodule/dir2/dir2_f.py

1
2
def dir2_fun():
print('dir2_fun')

Debug

Markdown
Markdown
可以看出其实不加__init__.py文件也是可以跑的,使用的是相对路径.
所以不打包时,有无__init__.py都不重要,因为相关的执行文件都在,是都可以执行的.

但是如果打包的时候没有__init__.py的话,那么相关的子模块是不打包的,所以肯定会报错.

main‘ is not a package

使用相对路径导入且通过 python xxx/xxx.py调用时会出现
例如:将test_main.py中

1
2
from dir1.dir1_1_f import dir1_1_fun
from dir2.dir2_f import dir2_fun

改成:
1
2
from .dir1.dir1_1_f import dir1_1_fun
from .dir2.dir2_f import dir2_fun

通过
1
python testmodule/test_main.py

调用便会报上面错误.
需要通过
1
python -m testmodule.test_main

调用

Unresolved reference

“项目结构”中的代码在pycharm中应该会提示如上信息,因为示例代码中的引用还是绝对引用,但是却没有根目录信息,虽然可以执行,但是会有如上提示.
一是改成相对路径,二是在前面再加上根目录名称,三是在Django中将根文件夹设置成source(但是这一步只是消除提示,并不解决代码结构问题)

ModuleNotFoundError: No module named ‘dir1’

这个就是在代码目录中使用了相对路径,但是在包调用的时候只将包名import了,使用的时候希望将其它函数索引出来便会遇到这个问题,因为是相对引用,所以仅导入包名时并不能索引到其下层函数.
这个代码结构不用改,需要在import的时候使用全路径import.
例如:
使用

1
from testmodule.test_main import test_main

而不是
1
2
import testmodule
testmodule.test_main.test_main # 这个便会报错: ModuleNotFoundError: No module named 'test_main'

总结

参考:使用相对路径导入包中子模块

在本地执行(不通过setup.py打包)的时候,有无__init__.py是没关系的,但是如果要打包且要使用子模块的话就必须含有__init__.py才能被视为子模块

建议都是用相对路径引用,在子模块之间使用“.”,“..”
使用相对路径后:
在本地测试的时候不能用python xxx/xxx.py来运行单元测试.需要改成python -m xxx.xxx
在打包后使用时,需要在import时使用全路径,不能是只导入顶层包名,然后通过包名索引

类似于人名/地名/组织机构名的命名体识别数据集,我花了几天时间标注了大约10000条视频/音乐/书籍数据.

数据的意义希冀能够基于此训练NLP模型识别句子中的视频/音乐/书籍等名称信息.

数据的标注过程:

  • 先纯手动提取标记了一部分(大约5000条),基于标注数据训练一个base模型,基于base模型重新审视校正标注数据.
  • 基于校正后的数据再训练一个模型,基于模型标注了另外约5000条数据.并对数据进行人工审核校验.
  • 最终数据集包含9632条数据.

理论上来说,任务也会是标准的NER任务.
难点:同一个名称可能是书籍也可能是视频(电视电影可能是由小说改编而来,有些场景关注书籍,另外一些可能关注视频),有些句子则只是提供了一长串并列的名称,可能没有更多的辅助信息;

示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
放暑假了,最近剧荒,陈情令也才一个星期更新三次,根本不够看,问问大家有什么好看的电视剧或电影推荐吗?最好是那种搞笑,温暖的那种,日剧也可以,好像道骏枝佑的剧还不错!
label: 陈情令/video

最近有没有好看的电视剧推荐,国内国外的都可以,前两天再追少年派,但剧情走向越来越扯,非常想给编剧寄刀片,现在想看些正常三观的剧,大家有没有推荐哒?
label: 少年派/video

最近有些剧荒啊,有什么好看的电视剧或者电影可以推荐么?我看的也比较杂,权力的游戏,黑色止血钳,最近看的韩剧囚犯医生是大爱啊,类似这种类型的可以给我推荐一些么?
label: 权力的游戏/video 黑色止血钳/video 囚犯医生/video

我个人比较喜欢听古风歌曲,然后呢,我歌单里面可以给你推荐几首,归去来兮琵琶行清明上河图好可以去试着搜索一些古装剧的主题曲或者插曲
label: 归去来兮/music 琵琶行/music 清明上河图好/music

不知道你喜欢什么类型的小说,最近在看十宗罪,悬疑烧脑类的,讲述的是公安部门打击违法犯罪的故事,现在已经出到第六部了,估计够你看一个月了。大冰写的书也可以尝试看一下,文艺小清新类型的
label: 十宗罪/book

最终提供的数据集转换成了标准的BIO标注格式,欢迎尝试使用.

Copyrights & Cite

LG: ourantech@163.com
Blog: https://www.ourantech.club/2019/08/31/029_视频音乐书籍标注数据/
Github: https://github.com/LG-1/video_music_book_datasets

  • 将要执行的内容编写到.sh脚本中(要注意路径和环境变量)
  • 创建修改定时任务: crontab -e
  • 打开日志(不是必须,但是最好打开,便于debug):
    vi /etc/rsyslog.d/50-default.conf
    sudo service rsyslog restart

  • 重启服务
    service cron restart

  • 查看执行记录:cat /var/log/cron.log
    检查执行记录及最终结果,执行记录有报错一定没执行成功,可以根据报错debug;执行记录没报错也不一定是执行成功,因为sh脚本可能做了相应的报错隐藏,要检查一下实际的执行结果确认.

需求

Word2Vec应用已经比较普遍.
基于类似思路,希望对句子级别内容实现向量化,以便后期使用时可以高效运算,比如寻找相似句子等.

目录

本篇练习主要讨论:

  • 如何评价句子向量化效果
  • 进一步探索必要性的背景
  • 参考的一些论文及阅读思考
  • 实际探索的方向
  • 探索实验结果

评价标准

在无标签情况下,或可使用最近邻查找或聚类等效果用以反映向量化的效果,作为特征进行分类可考虑.
特别地,Annoy挺好用.
另外,也可试试二维或者三维可视化看看效果.

背景

基于Word2Vec,尝试了最简单的词向量平均及TFIDF加权平均,结果表明,在短句(<20左右)的情况下,效果还不错.
但是句子一旦稍长,结果就不甚可用.文章级别就更勿论.
NIPS 2013 Deep Learning Workshop:NNforText.pdf中page20处也早就提到了这一点,亲身肉测发现确实.
(要是文档链接看不了的可以跟我吱一声)

想想其实可理解,不管是平均或者加权平均,都丢掉了句子结构信息,在短句情况下,句子结构本来也比较简单一些,所以可能信息丢失不多,尚可.
句子越长越复杂,结构越复杂,平均丢掉的信息也就越多,结果就扑街.

所以,基于Word2Vec,捕捉句子结构及顺序,可能会是一种值得探索的方向.

另外,不久之前的Bert或可考虑是否有用.当然,如果准备用Bert中间层导出,基本也就不用考虑LSTM模型了,因为结果肯定是有差距的.

论文阅读

Distributed Representations of Sentences and Documents
介绍了将文章视为另一个词的方法,文章所代表的“词”将刻画哪些未出现在当前上下文中的信息,故称:Distributed Memory Model of Paragraph Vectors(PV-DM).上下文信息通过滑动窗口得到.
论文介绍的Paragraph Vector方法从逻辑到实现上都比较通畅明晰,训练时间论文提到的是2.5万(平均230词)句子在16核机器上需要30分钟.个人觉得可以实验一下.
而且文章也间接总结了之前相关的一些论文,也可以作为索引.
ps1:在gensim的Doc2vec实现方法上用300万的中文句子做了尝试.结果表明,还是只能对短句起到比较好的效果,长句仍无法达到推进生产的标准.(所耗时间倒是跟论文所提差不多)
ps2:还试了一个Pytorch版本的Paragraph2vec,效果也不是很好,且面对新句子没法推导vec.但是思路还是可以借鉴的,或可在此基础上改进一下.

On sentence representations
是一篇介绍文章,主要介绍了句子表示方法.比较详细的介绍了最近的/较早的-监督/无监督句子表示方法.可以作为综述文章阅读.

BERT
bert-as-service
这个项目写得挺好的,耦合比较规范,但我就是不知道作者为啥把代码都写在了init.py中,但项目仍然是个非常好的项目.
直接可用.

探索方向

主要实验了mean Word2Vec/ paragraph vector / Bert embedding

Bert embedding的操作是输入句子,利用Bert预训练模型得到中间层结果(实验以得到的第12层为基准)
层越往前,可能效果会越有损失,但是速度可能会更快一点.

实验结果

文章从6月中开始写,但是伴随着实验结果不理想以及方法的探索,一直写到7月底,速度也是够慢的.

结果是,使用Bert embedding能够得到目前可以获取的最好结果,效果基本可以达到Word2Vec水平.
所以基本达到了可以应用的水平.
可以达到聚类可用的水平,近邻搜索用于召回或许还有点问题.

速度上来讲,120长度,基于CPU需要200ms左右,基于GPU需要30ms左右.
句子长度(需要保留的长度)越长速度也会越慢,层越往后也会越慢.

总结

目前Sentence2Vec基于最佳的Bert可以得到最好效果.
通过聚类可以发现,能够较好的刻画关键信息,即使句子比较长(<512),长度500左右基本可以覆盖中短篇章.
再往后估计需要期待下一步的NLP发展,仍需探索.

参考

[1]. Distributed Representations of Sentences and Documents
[2]. A Gentle Introduction to the Bag-of-Words Model
[3]. BERT
[4]. bert-as-service