你本来也不用自己手动进行词向量更新啊,你搞这么一出最后收敛到0那不是必然的么? @霍华德 老师的答案已经给你推导出来了。
实际上你问的这个问题很简单——只要把Embedding层本身也当成模型参数的一部分就可以了,一开始不使用外部词向量,直接随机初始化一个Embedding层,然后正常读入训练数据开始执行训练就可以了。在训练的过程中,如果指定Embedding层也是可训练的参数(pytorch里设置requires_grad=True)的话,那么在训练的时候Embedding层的参数也会被更新,就像更新LSTM的参数一样,对损失函数求导,通过BP更新Embedding层的参数,然后就可以实现你说的“同时训练词向量”了。
但一般情况下我们不会这么做——即使是不考虑梯度从损失函数出发,穿透LSTM到达Embedding层之后还能剩下多少(LSTM显然也不可能完全克服梯度消失问题),你这么一搞的话模型的参数总量就相当于你的LSTM的参数总量,加上Embedding层的参数总量。假设词表长度是10W,词向量维度是100的话,这种做法就意味着你的模型凭空多出了10W * 100 = 1000W的参数,显然你那点标注数据根本就喂不饱这么多参数,真这么玩的话直接就过拟合到姥姥家了。
这也就是为什么我们要使用预训练词向量——训练模型同时训练词向量,就意味着要使用宝贵的标注数据去填Embedding层这个大窟窿。而预训练词向量就完全不一样了——主流的词向量训练方法,比如早年间的word2vec,GloVe,或者近年来的各种Context-aware Embedding,都可以通过自监督(Self-Supervised)方法进行训练。也就是说,语料的词与词间共现关系(word2vec)或者上下文顺序(ELMo和BERT等)本身就是给模型的标注信息——这就意味着我们可以轻而易举地使用大量的无监督文本语料进行词向量训练。要知道,互联网时代,无监督文本语料本身的获取成本是很低的,基本上只要你往上堆算力堆模型就可以了。通过预训练词向量,不仅可以通过大量的文本获得质量更高的词向量,还可以在训练的时候直接把Embedding层当成常数(requires_grad=False),这样的话需要训练的参数就只有LSTM本身的参数了,让宝贵的标注数据可以好钢用在刀刃上。