当前位置:   article > 正文

【完结】囚生CYの备忘录(20221121-20230123)_廖是深

廖是深

序言

上一篇写到字数上限,刚好这对我来说也是一个转折点,11月20日晚跑出场地万米42分整的历史第二好成绩,极大扭转了连日不振的状态,让我再次相信身体依然年轻,没有什么事情是办不到的。这两天早睡早起,控制饮食,想要重新把生活安回到正轨,既是希望身体素质能够在当前节点上进而提升,也希望精神能够维持住高效的工作状态,尽快弥补之前的缺漏。

人总是艳羡辉煌的成就,却鲜有去发掘成就的起点,好大喜功计划宏大的目标,却摸不清当下定位。夏虫不可语冰,子非鱼安知鱼之乐?少一些观点的强加,多一些对道与志相异的尊重。

有时候我会思考以后应当怎样做一个父亲,这看起来似乎很遥远,又好像近在眼前。理想中子女能够跟我一样热爱跑步,小时候能教会TA编程乃至TA精通一门语言。但是又如何能做到这一点呢?这使我陷入困惑,我想是不会去强迫TA做什么事情,因为我也不喜欢被人PUSH去做事。看起来似乎只能听天由命,或许通过耳濡目染能够让TA逐渐认可并追随我的生活方式。

人无需为自己的信念与选择做任何辩护,只要无愧于己,只有心有愧疚的人才会千方百计地去自我粉饰。遗憾的是生活中我们很难真实全面地认识一个人,这需要长时间的沟通与不断深入的交流,因而更多时候的唯结果论就会慢慢扭曲人的信念与选择,乃至其原本的面貌。

所以,我从SXY身上看到的是她原本的面貌吗?亦或是我自己的样子,多少是有些共情在里头的罢,希望也能跟我一样重新找回生活的刺激点。

这是最后一年了,再不把握住,就如此遗憾终了,这样真的好吗?



20221121~20221122

PyTorch v.s. TensorFlow】有相当一部分函数在PyTorch和TensorFlow中都是共通的,因此两者有区别的部分作记录。

split函数原型:

  1. torch.split(tensor, split_size_or_sections, dim=0)
  2. tensorflow.split(value, num_or_size_splits, axis=0, num=None, name='split')

我一直想吐槽这个事情,axisdim明明是一个意思,但是torch和tf里的函数都是一个德性,有的函数用axis,有的函数用dim,如果没有代码提示就很容易记混。

这里主要关注两个函数的第二个参数,其实这个参数既有共通之处,也有不同之处。

  • split_size_or_sectionsnum_or_size_splits接受的参数是一个包含整数的列表List[int],此时两个函数效果是完全一样的,即按照给定的列表在指定dimaxis维上进行划分,具体如下:
# Split `x` of size [5, 30] into 3 tensors with sizes [4, 15, 11] along dimension 1
import tensorflow as tf
x = tf.Variable(tf.random.uniform([5, 30], -1, 1))
split0, split1, split2 = tf.split(x, [4, 15, 11], 1)
print(tf.shape(split0).numpy())	# array([5, 4], dtype=int32)
print(tf.shape(split1).numpy())	# array([5, 15], dtype=int32)
print(tf.shape(split2).numpy())	# array([5, 11], dtype=int32)

import torch
x = torch.randn(5, 30)
split0, split1, split2 = tf.split(x, [4, 15, 11], 1)
print(split0.size())	# torch.Size([5, 4])
print(split1.size())	# torch.Size([5, 15])
print(split1.size())	# torch.Size([5, 11])
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • split_size_or_sectionsnum_or_size_splits接受的参数是一个整数n,此时两个函数的效果完全不同,对于tf而言,这是在指定axis维上将张量划分成n等份,而对于torch,这是在指定axis维上将张量划分成每份长度为n的切片。

    具体而言,给定张量x的形状是(2, 3, 16),那么torch.split(x, 2, -1)tf.split(x, 8, -1)的效果都是将x划分成8份形状是(2, 3, 2)的切片。

此坑源于将MultiHeadAttention源码中的tensorflow改写成torch,源码对应部分:

# Split and concat
Q_ = tf.concat(tf.split(Q, num_heads, axis=2), axis=0) # (h*N, T_q, d_model/h)
K_ = tf.concat(tf.split(K, num_heads, axis=2), axis=0) # (h*N, T_k, d_model/h)
V_ = tf.concat(tf.split(V, num_heads, axis=2), axis=0) # (h*N, T_k, d_model/h)
  • 1
  • 2
  • 3
  • 4

应改写为:

self.size_of_head = int(d_model / num_heads)
# Split and concat
Q_ = torch.cat(torch.split(Q, self.size_of_head, dim=-1), axis=0) # (h*N, T_q, d_model/h)
K_ = torch.cat(torch.split(K, self.size_of_head, dim=-1), axis=0) # (h*N, T_k, d_model/h)
V_ = torch.cat(torch.split(V, self.size_of_head, dim=-1), axis=0) # (h*N, T_k, d_model/h)
  • 1
  • 2
  • 3
  • 4
  • 5

20221123~20221125

  • 陈嘉伟周二自测1500米,走的二道(因为一道散步的人太多),4’48"。去年校运会冠军4’47",亚军王兴耀4’57",季军嘉伟5’02",当时风很大,他状态也不是很好,所以这一年他到底吃啥药了,离大谱。
  • 下周日市运会,所以最近上的强度都特别高,周二12×400米间歇,第一次能开局连续跑出两组1’12"(每隔3秒出发一人,慢在前快在后,这两组我都能第一个跑完,后面两个比我快的都没能追上来,不过后面10组就只能被大佬肆意屠杀了),跑完腿就软了,剩下的也都勉强能进1’20",水平比之前提高了不少。
  • 不过这次市运会甲组取消了男子5000米和女子3000米的项目,所以我是没机会了。嘉伟和卢星雨被迫赶鸭子上架练800米和1500米。昨晚8×15个空杆(20kg)箭步跳+8×50米单脚跨步跳+8×50米跨步跳+2×20个立卧撑+一刻钟核心训练,加上热身的5000米(前3k4’30"配速带卢星雨,后2k跟嘉伟玩命,讲道理跟卢星雨跑的也不算快,但是都感觉有些吃力,最近指定是又不行了),今天果断浑身疼死。

几个有用的模板资源:

另外ConceptNet目前支持在线API,不过肯定是能在本地使用最好,ConceptNet官网里找到FAQ,里面给到了图谱下载的链接,不到500M

目前觉得DUMA和HRCA都太非人类了,不作分句就直接将整篇文章塞进去,这么粗暴真的好吗?对于DREAM来说可能还OK,但是RACE的文章实在是太长了,根本跑不动。


20221126

  • 1000米首次打开3’25"。本来今天腿疼得要死(力量训练后第二天是最疼的),本来还在犹豫要不要去训练,结果午睡起来下楼碰到李婷玉(后面还跟着廖是深,严重怀疑李婷玉已经把男票带自个房间里去),被两人押着去操场,躲也躲不掉。嘉伟在练4×400米接力(今天测下来是3’48")和800米,东哥放养我们几个没比赛任务的去跑5×1000米,因为剩下的只有我跑的最快,只能我来带队。第一个1000米就跑出3’25",第一圈用时1’16",说明后面掉速得厉害,如果能维持第一圈的速度,是可以打开3’15"的,速耐还得继续练。
  • 第一组就甩了第二卢星雨20多秒,后面我也没就认真跑了(第二组被内道散步的人给撞了两次,然后就泄气不想用力了),新来的两个男生居然连卢星雨都跑不过,不过卢星雨能把1000米跑进3’50"属实也很厉害,后面几个女生连4分半都跑不进。不过她只跑两组就摸鱼去了。

关于C++字符指针的问题:

众所周知整型指针int x=1, *p=&x; cout << p;输出的是x的地址,但是char c='a', *p=&c; cout << c;这是会出错的。

原因具体看下面的例子:

#include <iostream>
using namespace std;

int main()
{
	char s[10] = "abcdef";
	char t = 'a';
	char *p = s;
	cout << p << endl;
	char *q = &t;
	cout << q << endl;
	return 0;
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

显然输出p得到的是abcdef,这个是没有什么问题的;但是输出q就会有问题,原因是C++在输出字符指针时并不是输出其存储的地址,而是直接输出其指向的地址中存储的字符变量,但是一般来说如果字符指针*p指向的是一个字符串,当然就会正常输出,但是如果指向的是一个单一字符,那么问题就来了,运算符<<可不知道它到底接收的是指向什么东西的字符指针,只会依葫芦画瓢地按照字符串的情况进行输出,结果发现一直找不到结束符\0,于是就一路输出下去,直到溢出。

所以想要正常输出q中存储的地址,必须写成cout << (void*)q << endl;

别问我为什么又开始学C++了,说多了都是泪。


20221127~20221128

  • 昨晚脑子一热就跟sxy提了个约。她这学期call我是有点频繁,以前都是真的有事才会聊,可能现在真的是活得有点累,我觉得也应该回应她(或许我真的是很想见)。说起来她应该是欠我一顿饭的(没能吃到也是我活该),不过我们确实是太久不见了,陈年往事也没啥好提。可能我一直都有在刻意保持距离,总觉得靠得太近又会伤到彼此,有点担心自己会再脑子一热去表白,但是我也很害怕会永远错过,这已经是最后一年了。
  • 寒潮前夕,今天倒还算比较暖和,晚上碰到陈嘉伟看到他还是短袖短裤,显得我有点格格不入,他们本周日市运会有比赛任务的,最近每天都要加练,听说昨天深蹲都上到130kg了,属实狠人。
  • 节奏加紧,双线乃至三线并进,不拿出点看家本事是活不过下个月,无奈之举,我是真的不想这样过,但是晚上临走还是去操场小跑了一会儿。想想昨天上马刚结束,还有点小失落的,看到上财马协里李朝松和叶凯浩两人破三,用时238和241,分列38名和46名,真的是太强了,破三对我来说还是那么遥远的事情,目前全马破三配速我只能干到10km出头,而且总感觉接下来能训练的时间是越来越少了。

关于ANT(adoptive nerual tree,自适应神经树,论文链接),我觉得有一个很好的点,就是模型需要重训练。其实我一开始没看明白为什么模型可以不断生长,因为如果模型不确定,又该如何进行训练呢?后来看明白终于知道,从初始状态(一个根节点)开始,就要进行训练,然后每次训练后模型(树)都会加深一层(根据加深后的模型效果,计算熵值确定是否分支),预先会定义好树的最大深度,这样就一定会停下。显然这个训练开销是非常庞大的。

这种重训练的思想在类似的神经网络与遗传算法结合的方法也有使用,因为每次进行变异,都需要对模型进行重训练并确定其适应值,重训练的思路是值得关注的,可以理解为是训练好之后,进行一些后处理再进行新一轮的训练,从优化的角度来看,就是在优化到一定程度时,人为地根据合理设计好的指标对优化方向进行调整,以确保收敛到全局最优处。


20221129

  • 下午年级大会,听完感觉毕业也不是很难(是我飘了,但是我觉得总不至于一篇都发不出来吧)。
  • 会后回去换衣服,明后骤冷且有雨,肯定不适合训练,今天再不练实在说不过去。本来是准备去操场跑,许兴鹏想一起去健身房就一起去了,其实这是我第一次去健身房,果然全是肌肉猛男,惹不起。下午队里在训练,我试了一下无助力跑步机,发现完全适应不了,控制不了速度,要么一下子上天,要么就慢的要死,我看去年王兴耀能在这种无助力跑步机上4分配干10km还以为很好跑的。索性去正常跑步机上开15km/h(4分配)干5km,勉强维持状态,等寒潮过了准备抽空上长距离。

关于C++重载(指针&引用)的记录:

众所周知,重载书面上的定义特别简单,其实就是形参列表不同(类型不同或者参数顺序不同),但是一旦涉及指针和引用就很搞:

void f(int x) {}
void f(int* x) {}
void f(const int x) {} // 不能重载
void f(const int* x) {} // 可以重载
void f(int* const x) {} // 不能重载 
  • 1
  • 2
  • 3
  • 4
  • 5

注意上面的const int x是与int x冲突而无法重载且无法通过编译,但是const int* x就不会与int* x发生冲突,这就很神奇。

然后引用就更神奇了:

void f(int x) {}
void f(int &x) {}
  • 1
  • 2

这个其实是可以重载的,至少可以通过编译,但是你实际调用f(x)时就会报错ambiguous,因为编译器并不知道你到底要使用哪个函数。


20221130~20221201

  • 长者走好。与长者同乡,亦是校友,昨晚听闻此事,扬州中学的三年时光忽又浮现脑海,如今看来那或许是我人生最后一段兴趣使然、自由无畏、无忧无虑的时光。或许是因为长者曾在此读书的缘故,扬中始终都没有像其他学校push得很紧,没有逼迫也鲜有压力,尽管身边有比我更强大的人,或许是对手,但更多的一定是朋友。只是可惜,虽然我也曾站上顶点,却一次次挫败终而抱憾离去。
  • 以前一直觉得高中老班钱伟外强中干,一副老好人形象,不怎么管学生,讲课不过差强人意(本来数学课也没几个人听,他也清楚我们都会),考试成绩出来都是象征性地点几个有点退步去训两句,典型地走个流程。他分明就是运气好捡到了我们这个最好的班,每次包揽年级前10前20大半席位,前100也是1/3都在我们当中。但是现在想想他能用那种佛系风格30多岁做到年级组长,也确是一种本事。
  • 晚上冒着雨夹雪跟嘉伟热身干了5000米,然后脱掉羽绒服和长裤,短袖紧身裤上阵3’40"配速又干了3圈。这周状态养得很好,今晚想拉长距离,冬训就该练体能,可惜起步被冻得兴奋了,跑得特别快,但是本来就已经有点累了,于是很快崩垮。后来雨越下越大,做了两组负重箭步就就撤了,计划明天补上长距离。
  • 今年沪上第一场雪呢,你是否也看到了?sxy。每年到12月份都会有些许伤感,一年又过去,似乎又有很多事情没有做成,往事却又如昨日云烟。

照着伪代码(链接在代码中)写了一个DQN的基类,以备后用(其实我一直觉得推荐已经做的很好了,而且就推荐而言,做得一般好差不多也就够用了,人心怎么可能完全的量化呢?现在感觉就是把简单的问题强行复杂化):

# -*- coding: utf-8 -*-
# @author: caoyang
# @email: caoyang@163.sufe.edu.cn
# https://blog.csdn.net/weixin_43398590/article/details/107130244

import random
from copy import deepcopy

class BaseDQN:

	def __init__(self, n_epi, max_step, C, gamma=0.95):
		self.n_epi = n_epi			# 执行多少个episode
		self.max_step = max_step	# 生成序列的最大程度
		self.C = C					# 隔多少步更新Q网络
		self.gamma = gamma			# 折现因子
		self.initialize_buffer()	# 初始化内存buffer: 存储生成的序列
		
	def demo(self):
		initialize_Q_network()
		for epi in range(self.n_epi):
			current_state = sample_initial_state()
			for t in range(self.max_step):
				# Find next action
				feasible_actions = self.get_all_actions(state=current_state)
				if random.random() < 1e-2:
					# Epsilon greedy
					action = random.choice(feasible_actions)
				else:
					score = -float('inf')
					action = None
					for cand_action in feasible_actions:
						cand_score = self.Q(s=current_state, a=action)
						if cand_score > score:
							action = cand_action
							score = cand_score
				next_state = self.transaction(state=current_state, action=action)
				reward = self.get_reward(state=current_state, action=action)
				self.update_buffer(current_state, action, reward, next_state)
				sampled_buffer = self.sample_from_buffer()
				if t == self.max_step - 1:
					y_true = sampled_buffer['reward']
				else:
					_action, _score = self.find_optimal_action_Q_hat(state)
					y_true = sampled_buffer['reward'] + _score
				y_pred = self.Q(s=sampled_buffer['current_state'], a=sampled_buffer['action'])
				self.calc_loss_and_backward_propagation(y_true, y_pred)
				if t % C == 0:
					self.Q_hat = deepcopy(Q)

	# 初始化buffer
	def initialize_buffer(self):
		self.buffer = {'current_state'	: list(),	# s_i
					   'action'			: list(),	# a_i
					   'reward'			: list(),	# r_i
					   'next_state'		: list()	# s_{i+1}
					   }
	# 损失函数计算以及反向传播
	def calc_loss_and_backward_propagation(self, y_true, y_pred):
		pass
		
	# 初始化Q网络,hat Q直接复制Q网络
	def initialize_Q_network(self):
		self.Q = None				# Q(s, a)
		self.Q_hat = deepcopy(Q)
		
	# 采样一个初始状态
	def sample_initial_state(self):
		state = None
		return state


	# 给定当前state,找到所有可行的action
	def get_all_actions(self, state):
		actions = list()
		return actions

	# 给定state,计算根据\hat Q得到的最优action
	def find_optimal_action_Q_hat(self, state):
		feasible_actions = self.get_all_actions(state)
		score = -float('inf')
		action = None
		for cand_action in feasible_actions:
			cand_score = self.Q_hat(s=current_state, a=action)
			if cand_score > score:
				action = cand_action
				score = cand_score
		return action, score
		
	# 根据状态和行动得到下一个状态
	def transaction(self, state, action):
		next_state = None
		return next_state
		

	# 给定状态和行动计算奖励
	def get_reward(self, state, action):
		reward = None
		return reward

	# 将新生成的状态转移(或序列)更新到buffer中
	def update_buffer(self, current_state, action, reward, next_state):
		self.buffer['current_state'].append(current_state)
		self.buffer['action'].append(action)
		self.buffer['reward'].append(reward)
		self.buffer['next_state'].append(next_state)

	# 从buffer中采样一个batch的数据用于训练
	def sample_from_buffer(self):
		sampled_buffer = None
		return sampled_buffer
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110

20221202

  • 下午四点起跑,身体很轻,节奏却很差,配速4’02"干了10圈跑到力竭,差强人意,虽然我本意是万米起步。这周明显状态非常好,饮食充足、休息规律,心理也乐观许多,十二月最好能拉上半马。
  • 跑完看到一对情侣在做跑后拉伸,而且看拉伸动作和身上的装备,明显是女生要专业得多,我本以为卢星雨已经是珍稀物种了,实话说看得我有点小羡慕哈哈。

如果显存不够,可以考虑只将模型的一部分放在CUDA上计算,另一部分可以在CPU上计算,这样实现起来虽然有点冗余。比如你将BERT或者ROBERTA这种大模型放在自定义的Module中,model.to(‘cuda’)之后就直接炸了,还是只能通过参数把模型传进去,在CPU把结果计算出来再转到CUDA上,是可行的。


20221203

  • 市运会第一日,虽然我没有到现场,但是还是值得去记录的。有值得高兴的事情,陈嘉伟巨大突破,800米跑出2分11秒的超级成绩,在竞争极其激烈的甲组男子800米(56人参加)中跑出第6名,嘉伟真的是每次都让我瞠目结舌,每次都觉得他已经达到极限,却总能再次突破。他现在1000米肯定是已经能破三,5000米极有可能已经可以打破18分钟大关了。明天的1500米拭目以待。
  • 其他拿到名次的是女子4×100米(第8),男子110米跨栏(顾紫阳第6)。
  • 女子800米虽然全军覆没,黄嘉懿2’58"屈居第十,卢星雨3’01"(对于一个女博士来说已经是很强了,我现在800米估摸着也就勉强能开2’40",去比赛也就倒数前十)。男子4×100米无奈垫底(居然还让陈嘉伟上4×100米,这不把他累死)。明天的看点是男女的100米以及女子跳远,李婷玉和廖是深这对姐弟恋都是很有机会拿名次的。
  • 杨申宇太可惜了(400米破54秒的超级实力,队里短跑最强者),110米栏预赛受重伤,已经送医院了。他的预赛成绩足以拿到前三,而且缺了他这员大将,明天的男子4×400米凶多吉少(男子4×400米本来是有机会冲冠的)。
  • 有时候真的看到这些成绩就觉得自己还能再战一百年,虽然短跑和中长可能是没有机会了,但是5000米我还是有机会能破开19分钟大关,好想好想在赛道上这样热血沸腾一回,不然真的老了就再也没有机会了。

在这里插入图片描述
队旗左上比耶的是我的超人陈嘉伟(我愿称之为真男人,他这一年的恐怖进步我是看在眼里的,天赋无敌),捏着队旗右上角的是商院全能战神卢星雨,队旗左下坐着的是法学院博士兼队长李婷玉,最右边那个帅哥当然是东哥无疑。

我最近发现DUMA存在梯度消失问题,损失函数一直不变,挂一下DUMA的实现,想想怎么加点残差连接进去,或许参数初始化要改改:

# -*- coding: utf-8 -*-
# @author: caoyang
# @email: caoyang@163.sufe.edu.cn
# Implementation of DUMA

import torch
from torch.nn import Module, Linear, NLLLoss, functional as F

from setting import DEVICE
from src.tool.pretrained_model_tool import load_transformer_model
from src.module.attention_module import MultiHeadAttention

class DUMA(Module):
	"""Forward propagation algorithm of DCMN+
	Reference: [DUMA: Reading Comprehension with Transposition Thinking](https://arxiv.org/abs/2001.09415v5)
	Notice here we do not do sentence tokenization in DUMA (also in HRCA), but directly input the whole article tokens into model, which is different from Co-Matching and DCMN+
	This is feasible for DREAM, but in RACE, the number of total article tokens may be 1000+, which is hard for training.
	- Input:
	  - $P \in \R^{d×p}$ 
	  - $Q \in \R^{d×q}$
	  - $A = \{A_1, ..., A_m\}, A_j \in \R^{d×a}$
	- Output:
	  - $L \in \R^m$
	- Example:
	>>> args = load_args(Config=ModuleConfig)
	>>> kwargs = {'train_batch_size'		: 8,
				  'max_article_token'		: 128,
				  'max_question_token'		: 16,
				  'max_option_token'		: 24,
				  'duma_fuse_method'		: None,	# Change as 'mul', 'sum', 'cat'
				  'duma_num_layers'			: 2,
				  'duma_mha_num_heads'		: 8,
				  'duma_mha_dropout_rate'	: 0.,
				  'duma_pretrained_model'	: 'albert-base-v1',
				  'duma_encoding_size'		: 768}
	>>> update_args(args, **kwargs)
	>>> P_size = (args.train_batch_size, args.max_article_token)
	>>> Q_size = (args.train_batch_size, args.max_question_token)
	>>> A_size = (args.train_batch_size * N_CHOICES, args.max_option_token)
	>>> test_input = {'P'	: {'input_ids'		: (torch.randn(*P_size).abs() * 10).long(),
							   'token_type_ids'	: torch.zeros(*P_size).long(),
						   	   'attention_mask'	: torch.ones(*P_size).long()},
					  'Q'	: {'input_ids'		: (torch.randn(*Q_size).abs() * 10).long(),
						   	   'token_type_ids'	: torch.zeros(*Q_size).long(),
						   	   'attention_mask'	: torch.ones(*Q_size).long()},
					  'A'	: {'input_ids'		: (torch.randn(*A_size).abs() * 10).long(),
						   	   'token_type_ids'	: torch.zeros(*A_size).long(),
						   	   'attention_mask'	: torch.ones(*A_size).long()},
					  }
	>>> duma = DUMA(args=args)
	>>> duma_output = duma.forward(**test_input)"""
	loss_function = NLLLoss()
	def __init__(self, args):
		super(DUMA, self).__init__()
		self.p = args.max_article_token
		self.q = args.max_question_token
		self.a = args.max_option_token
		self.m = args.n_choices
		self.l = args.duma_encoding_size
		self.k = args.duma_num_layers
		self.fuse_method = args.duma_fuse_method

		self.multi_head_attention = MultiHeadAttention(d_model=args.duma_encoding_size, num_heads=args.duma_mha_num_heads, dropout_rate=args.duma_mha_dropout_rate)
		self.fuse_linear_x = Linear(self.l, self.l, bias=True)
		self.fuse_linear_y = Linear(self.l, self.l, bias=True)
		if self.fuse_method in ['mul', 'sum']:
			self.W = Linear(self.l, 1, bias=False)
		elif self.fuse_method == 'cat':
			self.W = Linear(2 * self.l, 1, bias=False)
		else:
			self.W = Linear(self.l, 1, bias=False)
		if args.load_pretrained_model_in_module:
			self.pretrained_model = load_transformer_model(model_name=args.duma_pretrained_model, device=args.pretrained_model_device)
			self.pretrained_model.eval()
		else:
			self.pretrained_model = None
	# @param P	: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size, max_article_token)
	# @param Q	: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size, max_question_token)
	# @param A	: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size * N_CHOICES, max_option_token)
	def forward(self, P, Q, A, pretrained_model=None):
		E_P, E_QA = self.encoder(P, Q, A, pretrained_model=pretrained_model)
		O = self.dual_multi_head_co_attention(E_P, E_QA)	# O: (batch_size, N_CHOICES, ?)
		L = self.decoder(O)									# L: (batch_size, N_CHOICES)
		return L

	# @param P		: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size, max_article_token)
	# @param Q		: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size, max_question_token)
	# @param A		: {'input_ids': tensor, 'token_type_ids': tensor, 'attention_mask': tensor}, tensor(batch_size * N_CHOICES, max_option_token)
	# @return E_P	: (batch_size, N_CHOICES, max_article_token, duma_encoding_size)
	# @return E_QA	: (batch_size, N_CHOICES, max_question_token + max_option_token, duma_encoding_size)
	def encoder(self, P, Q, A, pretrained_model=None):
		batch_size = P['input_ids'].size(0)
		size_of_split_choice = (batch_size, self.m, self.a)
		A['input_ids'] = A['input_ids'].view(*size_of_split_choice)
		A['token_type_ids'] = A['token_type_ids'].view(*size_of_split_choice)
		A['attention_mask'] = A['input_ids'].view(*size_of_split_choice)
		E_list = list()
		for i in range(self.m):
			concat_inputs = {'input_ids'		: torch.cat([P['input_ids'], Q['input_ids'], A['input_ids'][:, i, :]], axis=-1),				# (batch_size, max_article_token + max_question_token + max_option_token)
							 'token_type_ids'	: torch.cat([P['token_type_ids'], Q['token_type_ids'], A['token_type_ids'][:, i, :]], axis=-1),	# (batch_size, max_article_token + max_question_token + max_option_token)
							 'attention_mask'	: torch.cat([P['attention_mask'], Q['attention_mask'], A['attention_mask'][:, i, :]], axis=-1),	# (batch_size, max_article_token + max_question_token + max_option_token)
							 }
			E_list.append(pretrained_model(**concat_inputs).last_hidden_state.unsqueeze(1) if self.pretrained_model is None else self.pretrained_model(**concat_inputs).last_hidden_state.unsqueeze(1))
		E = torch.cat(E_list, axis=1)				# E		: (batch_size, N_CHOICES, max_article_token + max_question_token + max_option_token, duma_encoding_size)
		E_P = E[:, :, :self.p, :]					# E_P	: (batch_size, N_CHOICES, max_article_token, duma_encoding_size)
		E_QA = E[:, :, self.p:, :]					# E_QA	: (batch_size, N_CHOICES, max_question_token + max_option_token, duma_encoding_size)
		return E_P.to(DEVICE), E_QA.to(DEVICE)

	# @param E_P	: (batch_size, N_CHOICES, max_article_token, duma_encoding_size)
	# @param E_QA	: (batch_size, N_CHOICES, max_question_token + max_option_token, duma_encoding_size)
	# @return O		: (batch_size, N_CHOICES, ?) where ? could be duma_encoding_size or 2 * duma_encoding_size
	def dual_multi_head_co_attention(self, E_P, E_QA):
		O_list = list()
		for i in range(self.m):
			E_P_i = E_P[:, i, :, :]															# E_P_i	: (batch_size, max_article_token, duma_encoding_size)
			E_QA_i = E_P[:, i, :, :]														# E_QA_i: (batch_size, max_question_token + max_option_token, duma_encoding_size)
			MHA_1 = self.multi_head_attention(queries=E_P_i, keys=E_QA_i, values=E_QA_i)	# MHA_1	: (batch_size, max_article_token, duma_encoding_size)
			MHA_2 = self.multi_head_attention(queries=E_QA_i, keys=E_P_i, values=E_P_i)		# MHA_2	: (batch_size, max_question_token + max_option_token, duma_encoding_size)
			if self.k > 1:
				# Stack k layers
				for _ in range(self.k - 1):
					MHA_1 = self.multi_head_attention(queries=MHA_1, keys=MHA_2, values=MHA_2)							# MHA_1	: (batch_size, max_article_token, duma_encoding_size)
					MHA_2 = self.multi_head_attention(queries=MHA_2, keys=MHA_1, values=MHA_1)							# MHA_2	: (batch_size, max_question_token + max_option_token, duma_encoding_size)
			O_i = self._fuse(x=MHA_1, y=MHA_2)																			# O_i	: (batch_size, ?)
			O_list.append(O_i.unsqueeze(1))
		O = torch.cat(O_list, axis=1)																					# O		: (batch_size, N_CHOICES, ?)
		return O

	# @param O		: (batch_size, N_CHOICES, ?) where ? could be duma_encoding_size or 2 * duma_encoding_size
	# @return L		: (batch_size, N_CHOICES)
	def decoder(self, O):
		L_unactived = self.W(O).squeeze(-1)						# L_unactived	: (batch_size, N_CHOICES)
		L = F.log_softmax(L_unactived, dim=-1)					# L				: (batch_size, N_CHOICES)
		return L

	# @param x	: (batch_size, x_length, duma_encoding_size)
	# @param y	: (batch_size, y_length, duma_encoding_size)
	# @return	: (batch_size, ?) where ? could be duma_encoding_size or 2 * duma_encoding_size
	# I don not known the concrete implementation of the Fuse function in origin paper, as the author did not provide formulas or codes
	def _fuse(self, x, y):
		x_project = self.fuse_linear_x(x)					# x_project			: (batch_size, x_length, duma_encoding_size)
		y_project = self.fuse_linear_x(y)					# y_project			: (batch_size, y_length, duma_encoding_size)
		x_project_pooled = torch.max(x_project, axis=1)[0]	# x_project_pooled	: (batch_size, duma_encoding_size)
		y_project_pooled = torch.max(y_project, axis=1)[0]	# y_project_pooled	: (batch_size, duma_encoding_size)
		if self.fuse_method == 'mul':
			return torch.sigmoid(x_project_pooled * y_project_pooled)						# @return	: (batch_size, duma_encoding_size)
		elif self.fuse_method == 'sum':
			return torch.sigmoid(x_project_pooled + y_project_pooled)						# @return	: (batch_size, duma_encoding_size)
		elif self.fuse_method == 'cat':
			return torch.sigmoid(torch.cat([x_project_pooled, y_project_pooled], axis=-1))	# @return	: (batch_size, 2 * duma_encoding_size)
		else:
			# Inspired from FuseNet in https://github.com/Qzsl123/dcmn/blob/master/dcmn.py
			p = torch.sigmoid(x_project_pooled + y_project_pooled)			# p			: (batch_size, duma_encoding_size)
			return p * x_project_pooled + (1 - p) * y_project_pooled		# @return	: (batch_size, duma_encoding_size)
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85
  • 86
  • 87
  • 88
  • 89
  • 90
  • 91
  • 92
  • 93
  • 94
  • 95
  • 96
  • 97
  • 98
  • 99
  • 100
  • 101
  • 102
  • 103
  • 104
  • 105
  • 106
  • 107
  • 108
  • 109
  • 110
  • 111
  • 112
  • 113
  • 114
  • 115
  • 116
  • 117
  • 118
  • 119
  • 120
  • 121
  • 122
  • 123
  • 124
  • 125
  • 126
  • 127
  • 128
  • 129
  • 130
  • 131
  • 132
  • 133
  • 134
  • 135
  • 136
  • 137
  • 138
  • 139
  • 140
  • 141
  • 142
  • 143
  • 144
  • 145
  • 146
  • 147
  • 148
  • 149
  • 150
  • 151
  • 152
  • 153
  • 154

20221204

  • 市运会谢幕,队内拿到的名次包括一块金牌(女子跳远),2个第6(男子跨栏+男子800米),3个第7(女子4×400,女子跳远,?),3个第8(男子4×400,女子4×100,?)。女子组相对竞争小一些,比如4×400一共就10个队参加,所以女生其实只要肯练基本上还是挺好拿名次的,但是径赛还是要有硬实力的,黄嘉懿和卢星雨在1500米分获第9(5’58")第10(6’04"),真的就是差一点点,特别可惜,而且今天还是雨战,对男生是无所谓,女生还是太勉强了。
  • 然后重头戏是陈嘉伟的1500米,此前他队内自测(跑的2道)成绩是4’48",当时预测正式比赛能稳进4’45",今天奇迹般跑出4’40"(去年校运会冠军4’47",王兴耀4’57"),1000米分段用时3’07",然而即便如此都未能跑进前八(46人排名11),男子确实竞争太激烈。后来我看了一下乙组5000米,2人跑进15分钟,陈嘉伟如果能跑到十八分整,也只能排倒数第四(21人),前八全部跑进16分钟,太残暴了。
  • 市运会四年一届肯定是再没有机会参加了,虽然也有许多人跟我一样遗憾,ysy受伤,而且因为今年两天都有雨,跳高项目全部取消,所以gzj等于是去公费吃喝了两天,啥事儿没做。下午去操场慢跑10圈,刚好看到他们回来,我又想起去年高百,那时候我也是同他们一样兴奋,清晨5点出发,第一棒就跑出43分整的10km路跑PB,走一天路都没觉得累,直到回宿舍瘫倒在床,小腿酸涨得再起不能。
  • 年轻真好。

我终于发现问题在哪儿,dual_multi_head_co_attention里E_QA_i取成E_P了,所以我改完又在MHA上加了残差连接(直接把MHA_1+E_PMHA_2+E_QA),然后现在看起来确实正常多,但是loss波动得厉害,感觉又explosion了。

有没有办法让torch运算都在CUDA上?只要运算完就把变量全部撤到CPU中,比如我要计算t3=t1+t2,那么只要执行到这个时,将t1t2放到CUDA上,完事算完再把它们拿下来,因为显存要比内存小得多,虽然转移变量的位置很费时间,但是这样也相当于是用时间换空间了,如果torch里有办法直接配置就好了。


20221205~20221206

  • 寒潮过境后的晴朗冬日,下午场地万米自测41’15"(PB),断断续续练了三个月,才终于恢复到巅峰。可是年底也没有比赛能跑,怅然若失。
  • 本周日有个院庆40周年的跑步活动,在滨江大道一条路线5km的路线,如果没被抓去写本子就去凑个热闹,手头事情确实紧,而且今天七号楼羊了一个,不过风向是不让封校的,所以权当无事发生。
  • 昨晚跟组里研二的学妹讨论这次科技部的课题,她忽然说想要读博,我惊诧不已,第一感是找工作形势不好,至少也是对女生不利,第二感就是博士也越来越卷了要,就像有一双无形的手在将新生力量赶尽杀绝。不知道sxy选调面试有没有过,多一条后路总是好的。而我已经无路可退了。

关于弱监督,我估摸着这就是不知道哪个大聪明发明出来用来申报项目的新名词,然后这个词现在看来就很歧义,大致可以指代四种不同的建模思想:

  1. 等价于半监督,即存在大量无标注数据的情况下,如何训练可靠模型。
  2. 指数据的标签是弱标签,具体而言,比如只告诉你图片中有汽车,但是实体识别需要具体指出汽车所在的位置,前者是弱标签,后者则是强标签。这个就有点强行套用的感觉,因为本质上这也可以划归为特征工程问题,弱标签直接当成特征来用也是可以的,或者使用弱标签进行预训练也是可行的。
  3. 训练数据中存在噪声,这也是一种弱监督训练问题。有人说这个其实是数据预处理的问题,有噪声那就去噪不就好了,首先去噪本身也不是一件很容易的事情,更重要的是,有一些特殊的任务本身就是需要数据中存在噪声,比如语音问答,因为语音转文字难免存在噪声的,所以有时候为了模拟实际应用,会故意在问答的输入中增噪来模拟实际情况,使得模型更具有鲁棒性。
  4. 第四种其实是从第三种引申出来的,就是指文本中一种特殊的噪声——歧义,即存在多义词或者整句句意存在歧义的问题。这个我看到的一个是文本分类问题,因为目前通常的文本分类的处理比较依赖种子词(比如情感分类中的情感词),但是种子词如果存在多义情况,那么就会使得问题变得复杂,这里要做的工作有点类似WSD,即单词消歧。

20221207~20221210

  • 这三天困死,每天都没时间睡午觉,早上八点半到,晚上九点半走,这已经是我能容忍的极限了,不睡午觉还是不行,要不然下午四点基本上就要睁不开眼了,晚上效率贼差。
  • 周二PB完万米之后,周三混了五圈,周四晚是想要训练的,但是刚换完衣服出实验楼就发现下雨,悻悻而归,周五又是混了五圈,今天不能再混了,但是下午还是下雨,所以只能晚上跑了10圈找找状态,这三天还是太伤了。
  • 周四听师兄博士论文答辩过了,只延毕了半年,成果很丰硕,稳稳地能拿双证,现在压力到了我这一边…

预训练这块最近发布一篇很好的survey:arxiv:2106.07139,其实整体上来看我们是不可能依托学校去研究这种级别的模型,就8块GPU能做啥,最近拼死拼活DCMN+的结果都跑不出来。

这个基本上是把从NLP里的预训练,到多语言多模态的预训练,以及一些数据功效的内容都讲得算是比较明白了(包括一些模型压缩的技术)。

  1. 弱模型 -> 弱标签 -> 混合自训练(弱标签感知的损失) -> 强数据验证 -> 微调 -> 强模型
  2. 数据增强(无标签数据收集,无标签数据预训练,种子词自动生成语料,外部知识源)
  3. 特征增强(引入更多特征,有1篇是用元数据增强的,2020.emnlp-main.670.pdf,不过没太看明白,都是文本分类,主要还是依赖种子词)
  4. 算法:CRF, HMM, 这里典型的隐马尔可夫模型,相当于弱标签即可以观察到的信号,然后去预测真实标签,这个在NERT中是比较常用的
  5. 聚类方法,对未标注或弱标签数据进行虚假标注或是标签增强
  6. data-programming方法:https://aclanthology.org/2021.emnlp-main.104 这个讲的是对话分割,但是没太看明白,
  7. 其他可能的点:
    • 零样本学习(ZSL):https://www.zhuanzhi.ai/paper/f6a555d46d100efdc534956cd7818c8f
    • 高效训练,那篇综述的6.2节提到了一些

20221211

  • 早上去滨江大道参加院庆的跑步活动,其实我出地铁站翻地图的时候就发现旁边是崂山六村,我就一直觉得很眼熟,直到开跑才想起来是sxy很久很久之前给我发的定位是住在那边。早知道提前问问有没有搬走,我估计是还没搬,想叫出来又觉得太唐突,而且一身臭汗好像也不太合适,还是算了。
  • 本来看有三四个师兄穿得还挺专业,看起来应该是跑马的。结果全程就是我一个人独自领跑,后面连个人影都看不到。滨江修了一条跑步用的塑胶跑道(虽然已经完全没有弹性了),但是那个路真的一言难尽,全是上下坡,特别难受,有两个地方居然是W型的上下坡路段,起手4分配给我跑崩了,最后是4’20"的配速收尾,不过作为一场爬坡跑训练也挺不错的。大概前500米我还能看到有个兄弟在后面奋力追我,后面就完全看不到人影。
  • 下午回来就是干活,其实我知道肯定会有事,但是就想早上溜掉。最近学校里风言风语很多,据说
    声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/盐析白兔/article/detail/561478
推荐阅读
相关标签