更新囚生CYの备忘录(20221121-)

Posted 囚生CY

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了更新囚生CYの备忘录(20221121-)相关的知识,希望对你有一定的参考价值。

序言

上一篇写到字数上限,刚好这对我来说也是一个转折点,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])
  • 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)

应改写为:

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)

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;

显然输出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)  // 不能重载 

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

然后引用就更神奇了:

void f(int x) 
void f(int &x) 

这个其实是可以重载的,至少可以通过编译,但是你实际调用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

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完结囚生CYの备忘录(20221121-20230123)

更新囚生CYの备忘录(20230216~)

更新囚生CYの备忘录(20230216~)

继续更新囚生CYの备忘录(20220906-)

完结囚生CYの备忘录(20220525-20220813)

完结囚生CYの备忘录(20220525-20220813)