对,我觉得你的思路非常值得做实验。而且你说的“类似基函数”这个比喻很准确:不一定要直接把“句子理解”当成一个巨大任务,而是先寻找一组最小的语言操作原子,再观察复杂语言现象能不能由这些原子组合出来。
如果你的目标是测试一种新的 NLP 方法,我建议不要从“分词、词向量、Transformer”这些现成模块出发,而是从语言到底需要哪些基本操作来拆。
一、先把自然语言处理拆成几个最基本的动作
我会把它分成 7 类。
1. 指称:这个东西是谁?
最基本的问题:
“猫” → 一个对象/概念
“北京” → 一个地点
“他” → 某个已经出现的人
可以叫:
REFER(指称)
例如:
小明喜欢猫。
至少需要建立:
小明 → 人
猫 → 动物2. 属性:它是什么样?
把一个对象和一个属性连接起来。
猫很大。
变成:
猫 → 大或者:
小明很聪明。
小明 → 聪明这是非常基础的操作:
ATTRIBUTE(x, a)
3. 关系:两个东西之间有什么关系?
例如:
小明喜欢小红。
实际上就是:
喜欢(小明, 小红)再比如:
猫追老鼠。
追(猫, 老鼠)我认为这是 NLP 中非常重要的一个“基函数”。
因为很多语言最终都可以还原成:
对象 + 对象 + 关系
4. 动作:某个东西发生了什么变化?
例如:
小明打开门。
不是简单的:
小明 → 打开
门 → 被打开而是一个事件:
事件:
动作 = 打开
执行者 = 小明
对象 = 门也就是:
EVENT(action, agent, object)
复杂语言里的“事件”“过程”“因果”,可能都是从这个东西组合出来的。
5. 否定:不是
这是一个特别值得测试的基本操作。
小明喜欢猫。
喜欢(小明, 猫)变成:
小明不喜欢猫。
NOT(喜欢(小明, 猫))注意:
否定不是一个普通词,而是一种对已有结构进行操作的函数。
这就已经很接近你说的“基函数”了。
6. 组合:把两个东西组成一个更大的东西
例如:
红色的苹果
可以认为:
苹果
↓
ATTRIBUTE(苹果, 红色)再比如:
小明喜欢红色的苹果。
就是:
喜欢(
小明,
ATTRIBUTE(苹果, 红色)
)于是语言开始出现递归组合。
这可能才是你这个研究方向最核心的地方:
复杂语言未必需要新的基本运算,只需要已有运算不断组合。
7. 逻辑操作:如果、因为、所以、但是
再往上一层:
如果下雨,小明就不出去。
可以拆成:
IF(
下雨,
NOT(出去(小明))
)再比如:
因为下雨,所以小明没有出去。
CAUSE(
下雨,
NOT(出去(小明))
)再比如:
小明很聪明,但是他很懒。
AND(
聪明(小明),
懒(小明)
)或者:
CONTRAST(
聪明(小明),
懒(小明)
)于是:
否定、条件、因果、并列、转折,都可以成为更高层的组合操作。
二、这样一来,可以建立一个“语言基函数表”
我甚至建议你先不要追求很多。
可以从下面这套最小集合开始:
| 基本操作 | 功能 | 例子 |
|---|---|---|
REFER | 指向对象/概念 | 猫 |
ATTRIBUTE | 对象具有属性 | 猫→黑 |
RELATE | 建立关系 | 喜欢(小明,猫) |
EVENT | 表示事件 | 打开(小明,门) |
NOT | 否定 | 不喜欢 |
AND | 合并 | A并且B |
OR | 选择 | A或者B |
IF | 条件 | 如果A,则B |
CAUSE | 因果 | A导致B |
COMPARE | 比较 | A比B大 |
TIME | 时间关系 | A之后B |
SPACE | 空间关系 | A在B里面 |
然后刻意限制模型只能使用这些操作。
这就变成一个非常有意思的实验。
三、例如把一句很复杂的话“编译”一下
比如:
因为昨天晚上下了很大的雨,所以小明没有去公园,但是小红去了。
可以逐层拆:
雨(昨天晚上)
大雨(昨天晚上)
去(小明, 公园)
NOT(去(小明, 公园))
去(小红, 公园)
CAUSE(
下雨(昨天晚上),
NOT(去(小明, 公园))
)
CONTRAST(
NOT(去(小明, 公园)),
去(小红, 公园)
)注意这里发生了一件很重要的事情:
句子本身没有消失,只是被转换成了一个结构。
那么你的新 NLP 方法就可以测试:
给定这套基础操作,能不能重新生成原来的语言?
如果可以,就出现了:
自然语言
↓
基本操作
↓
组合结构
↓
复杂语义
↓
自然语言这实际上已经非常接近一个“语言编译器”的思想。
四、我觉得你真正应该测试的不是“理解”,而是“组合能力”
这是我认为你这个想法最有意思的地方。
传统 NLP 很容易测试:
“这句话是什么意思?”
但你可以换一个问题:
一个语言系统能不能只用少量基本操作,组合出越来越复杂的语言结构?
例如规定只有:
A = 指称
B = 属性
C = 关系
D = 否定
E = 因果
F = 条件然后测试:
一级
猫
红猫
猫吃鱼二级
红猫吃鱼
小明喜欢红猫
小明不喜欢红猫三级
因为小明喜欢红猫,所以他买了一只。四级
如果小明喜欢红猫,那么当他看到红猫的时候,他就会买一只。五级
如果小明喜欢红猫,那么即使价格上涨,只要他认为这只猫值得,他仍然会购买。然后观察:
复杂程度增加以后,你的算法需要增加新的基本函数吗?
如果不需要,只需要不断组合已有函数——
那就非常有意思了。
五、甚至可以做一个“语言基函数实验”
我建议你第一版不要碰大型语料库。
自己做一个非常小的测试集。
比如只使用:
20个名词
人、猫、狗、鱼、苹果、汽车、学校……20个关系
喜欢、吃、看、追、拥有、进入……10个属性
大、小、红、蓝、聪明、漂亮……10个逻辑操作
不、并且、或者、如果、因为、所以、但是……然后随机组合。
例如:
猫 + 吃 + 鱼
小明 + 喜欢 + 猫
小明 + 不喜欢 + 猫
如果 + 小明喜欢猫 + 那么 + 小明买猫
因为 + 猫饿了 + 所以 + 猫吃鱼然后逐渐增加组合深度:
深度 1
深度 2
深度 3
深度 4
深度 5
……最后画一条曲线:
语言复杂度 ↑ → 算法性能 ↓
看看你的方法在什么地方开始崩溃。
六、而且这和你之前想到的“语义扩散”其实可以接起来
你之前提出过一个想法:
不一定要计算所有词之间的高维向量相似度,而是把相近的词连接起来,然后通过 2 度、3 度关系进行语义扩散。
这个想法和现在这个“基函数”思路其实可以形成一个更大的架构。
可以变成:
自然语言
↓
语言基本单元
↓
┌─────────┴─────────┐
↓ ↓
词/概念节点 操作节点
↓ ↓
语义关系网络 基本语言函数
└─────────┬─────────┘
↓
组合
↓
语义结构
↓
复杂理解也就是说,你研究的可能不再是:
“如何让一个神经网络更聪明?”
而是一个更基础的问题:
“自然语言的复杂性,能否由有限数量的语义原子 + 有限数量的组合操作产生?”
这个问题我觉得非常值得认真做实验。
而且如果要验证,我建议下一步直接建立一个 “NLP 基函数最小集合 v0.1”,把每个函数定义成严格的输入、输出和组合规则,然后设计 100~1000 个由简单到复杂的测试句子。这样你的新 NLP 方法就可以和 Transformer/词向量方法做一个非常干净的对照实验。