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

Posted 囚生CY

tags:

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

序言

《白马非马》

月晕梦觉三更外,辗侧不寐天欲白。
长街小巷人不在,闭户方晓余空斋。
淫行庸碌民风改,凛冬难去花未拆。
粉饰贪墨莫仇忾,时有灾异毋自哀。

——囚生

辗转多时我还是回到了这里继续写,希望这篇可以写得更久一些,各种意义上。

本来是决定死磕到底,因为很想亲眼看看上位者何时才愿意在这荒唐的局面下做出让步。可是忽然又觉得拿别人的过错来惩罚自己实非明智之举,尤其是伙食质量日益参差不齐,越发无法满足日常训练需求。如果大多数人都坚定地选择留下来,必然是会对决策产生冲击的,可惜事与愿违。

走得很匆忙,提前一天半买票,然后赶忙办好各项事宜。虽然很不愿意这么形容,但是更像是一场大逃亡。出站后就被贴上各种标签集中管控,在被站务人员吆喝着快点走的时候,俘虏即将进入集中营的既视感跃然心头,前面的老爷子死活不肯加快步伐,透过背影能看出骨子里的那股倔强。

好在走出封楼警戒线后如释重负,两个月的高压状态得到缓解。还认识一个同行回无锡的学妹,结伴走了一遭,有种跟活人打交道的新鲜感。也算不得太坏罢。

最后是一些罔论

  1. 我一直认为要多了解少发声,即悉实而慎论,因为有一百个人赞同你,就会有一千个人中伤你,从cdb劳神费力写了一个月《昨日谈》后选择弃坑可见一斑。但是每个人都不发声,这就是一件好事吗?也许某些场合下,我们只是被禁锢了声带,使得本该属于强弱群体之间的矛盾莫名其妙地转变成弱势群体内部的矛盾。
  2. 我一直以来还有一个坚定的观点不争对错,因为历史无法重演,无法证明也无法证伪若干决策事实上的合理性,甚至连合理性本身就缺少客观的评价方式,因此我总是会固执己见地走自己的歪门邪道。但是在这次的事件上我是真的动摇了,或许80%的人认为正确还不足以证明正确、99%还不能、那么99.99%呢?其实都没有区别,只要剩下的0.01%让99.99%发不出声,那0.01%就是100%。

声明:本文的观点仅代表个人看法,不针对任何对象,请勿妄加揣度。本文将以备忘录形式展开更新直至字数到达文章可发布的上限值,目的是督促自己每天能学到些有用的新东西,与诸君共勉。


文章目录


2022-05-25

关于数组拼接的易忘易混点(以torch.tensor类型为例,numpy.ndarray以及tensorflow类似),即区分torch.cattorch.stacktorch.vstacktorch.hstack四个函数:

  • 一维情况

    假定有2个形状为torch.Size([3])的数组a1a2,则有如下结论:

    torch.cat([a1, a2], axis=0)的形状为torch.Size([6]),即是左右拼接,且axis参数只能取0,不能取别的值。
    torch.stack([a1, a2])的形状为torch.Size([2, 3]),即是上下拼接;
    torch.hstack([a1, a2]])的形状为torch.Size([6]),等价于torch.cat([a1, a2], axis=0)
    torch.vstack([a1, a2]])的形状为torch.Size([2, 3]),等价于torch.stack([a1, a2])

  • 二维情况

    假定有2个形状为torch.Size([3, 4])的数组a1a2,则有如下结论:

    torch.cat([a1, a2], axis=0)的形状为torch.Size([6, 4]),直观上看是上下拼接;torch.cat([a1, a2], axis=1)的形状为torch.Size([3, 8]),直观上看是左右拼接;总结axis取值决定结果的形状是在第几维上进行叠加;
    torch.stack([a1, a2])的形状为torch.Size([2, 3, 4]),即是上下堆叠;
    torch.hstack([a1, a2]])的形状为torch.Size([3, 8]),等价于torch.cat([a1, a2], axis=1)
    torch.vstack([a1, a2]])的形状为torch.Size([6, 4]),等价于torch.cat([a1, a2], axis=0)

  • 三维情况

    假定有2个形状为torch.Size([3, 4, 5])的数组a1a2,则有如下结论:
    torch.cat([a1, a2])的规律与二维情况相同,即取决于axis的取值将会得到torch.Size(6, 4, 5)torch.Size(3, 8, 5)torch.Size(3, 4, 10)三种不同的结果;
    torch.stack([a1, a2])的形状为torch.Size([2, 3, 4, 5]),仍是上下堆叠;
    torch.hstack([a1, a2]])的形状为torch.Size([3, 8, 5]),等价于torch.cat([a1, a2], axis=1)
    torch.vstack([a1, a2]])的形状为torch.Size([6, 4, 5]),等价于torch.cat([a1, a2], axis=0)

  • 更高维情况的规律总结torch.cat最好理解,根据axis的取值决定最终形状(除axis所在维外,其他维各个数组的形状必须相同),torch.hstacktorch.vstack总是分别对应torch.cat取值axis=1axis=0的情况,torch.stack总是会使得结果的维数+1,即简单的将所有数组拼凑起来,但是必须要求所有数组的形状都相同。

    另外numpy的情况完全相同,其中torch.cat替换为numpy.concatenate


2022-05-26

  • 目前计划花一周时间把斯坦福的CS224N-winter2022的课程从头到尾过一遍,最好能把课程作业也一起做掉,更一篇长博客,CAIL2021暂时搁置,实话说CAIL2021真的是有认真投入,却迟迟不能有所进展,总不能在一棵树上吊死,换件事情做调整心态。
  • 这两个月学得太少,想必已是落后很多,对自己有些失望。好在目前多少还能有点容错率,人一定是要不断学习才能保持状态的,周更博客一定程度还是可以鞭策自己进行高效的知识汲取,太怠惰了cy。
  • 29号应该就能走,新通知是5+2+7。佳明FR245后天到货,跟老妈放了狠话今年夏天必将10公里跑进40分钟,谁也别想阻挠我。

关于数组形状重构的易忘易混点(以torch.tensor类型为例),即区分torch.reshapetorch.viewtorch.transposetorch.permute

import torch as th
t1 = th.FloatTensor([
	[
		[1, 2, 3, 4],
		[5, 6, 7, 8],
		[9, 10, 11, 12],
	],
	[
		[-1, -2, -3, -4],
		[-5, -6, -7, -8],
		[-9, -10, -11, -12],
	]
])
print(t1.view(3, 2, 4))
print(t1.reshape(3, 2, 4))
print(t1.permute(1, 0, 2))

输出结果为:

tensor([[[  1.,   2.,   3.,   4.],
         [  5.,   6.,   7.,   8.]],

        [[  9.,  10.,  11.,  12.],
         [ -1.,  -2.,  -3.,  -4.]],

        [[ -5.,  -6.,  -7.,  -8.],
         [ -9., -10., -11., -12.]]])
tensor([[[  1.,   2.,   3.,   4.],
         [  5.,   6.,   7.,   8.]],

        [[  9.,  10.,  11.,  12.],
         [ -1.,  -2.,  -3.,  -4.]],

        [[ -5.,  -6.,  -7.,  -8.],
         [ -9., -10., -11., -12.]]])
tensor([[[  1.,   2.,   3.,   4.],
         [ -1.,  -2.,  -3.,  -4.]],

        [[  5.,   6.,   7.,   8.],
         [ -5.,  -6.,  -7.,  -8.]],

        [[  9.,  10.,  11.,  12.],
         [ -9., -10., -11., -12.]]])

规律总结

  1. .permute实现的是维数交换,一般是可以得到所期望的结果,以.permute(1, 0, 2)为例,原数组在[i, j, k]位置的元素,在新数组中转移到[j, i, k]。如在机器学习常用于多组同类型的数据通过torch.stack堆叠后,将torch.stack多出来的那一维调整到其他位置(比如为了将batchsize维调整到最前面);
  2. torch.transpose每次只能置换两个维度的次序,PyTorch中文文档中的翻译有误导性,容易误解为只能对二维矩阵进行转置;以tensor.permute((1, 2, 0))为例,其等价于tensor.transpose(0, 2).transpose(0, 1)
  3. .reshape.view方法得到的结果是完全相同的,本质就是先创建一个形状为参数值的空数组,然后按照原数组的维数顺序依次将所有数值填入空数组,因此很可能会得到一个数据完全被打乱的结果;
  4. 特别注意的一个点是.view方法是直接在原张量所在的储存地址上直接进行转换,.reshape则是重新开辟新的内存空间,因此前者更快也更节约资源。但是.view仅针对连续存储的张量(如直接使用torch.FloatTensor开辟的张量),而类似torch.stack拼接的张量得到的是不连续存储的,则无法使用.view方法进行转换。其他无法使用.view方法进行转换的方法目前尚不明晰。

2022-05-27

  • 无事可做,一整天都在狂肝CS224N,午觉都没睡,总归还是学到不少东西,等笔注详实一些后先发出来,后续再接着更新。作业的答案也在我的GitHub仓库同步更新,争取一周之内把这事儿给结掉。
  • 佳明FR245已经到货,只是这两天训练时把膝盖给磕破了,还好手头有创可贴应急。昨天老妈送了荔枝和苹果,说起来因为这两个月吃不到水果,身上好多伤口都迟迟不能消退,以前天天吃水果没有感觉,还以为自然愈合是很平常的事情,直到流了半个月鼻血后,才知道有的吃是多么奢侈的事情。

Python程序计时可以使用timeit中的timertimeit方法,前者为单次计时,后者默认100000次计时取前三快的用时取平均。注意使用到的变量需要在globals参数中以字典的形式进行声明,比如:

import timeit
import random

def sample(n):
	samples = []
	for i in range(n): 
		samples.append(random.choice(list("ABC")))
	return samples

n = 10
timeit.timeit('sample(n)', globals='random': random, 'sample': sample, 'n': n)

在Jupyter中可以直接使用魔法命令%timeit对指定代码运行时间进行计时:

%timeit sample(10)

也可以自定义装饰器来对指定函数进行计时,在指定需要计时的函数定义前添加@timer装饰,每次运行函数即可输出运行时间:

import time
import random
from functools import wraps

# 程序计时的装饰器
def timer(func):
	@wraps(func)
	def wrapper(*args, **kwargs):
		start_time = time.time()
		returned = func(*args, **kwargs)
		end_time = time.time()
		print('Function `` runtime is  seconds.'.format(func.__name__, end_time - start_time))
		return returned
	return wrapper

@timer
def sample(n):
	samples = []
	for i in range(n): 
		samples.append(random.choice(list("ABC")))
	return samples

sample(10)

若忽略装饰器定义中wrapper函数的return,则被装饰的函数的返回值将无法获取:


2022-05-28

  • 肝完前四讲,发现CS224W也不错,可以一并肝掉。
  • 估计还得多挨一天,不过效率很好,反正回去也是一样关禁闭,不如再白吃白喝两天。
  • CSDN现在字数限制太过于苛刻,以前那种长博客根本发不出来,只能分篇发布,感觉这篇可能写不到一个月可能就要封篇,很无语。要不之后就用专栏专门收录这类博客吧,懒得吐槽了。

CS224N学习随想:

  1. 负采样的核心在于定义损失函数,其目的既能扩充规模,也能平衡样本频率。
  2. 依存分析以及句法分析目前看来有点类似证明图的生成,很类似基于路径的一些方法,因此可能动态规划与强化学习可能是流行的方向,虽然并没有查阅到最新的研究。

顺手记录一下DataFrame.apply函数的易忘点:

axis=1时,apply中的apply_func的参数表示数据表一行的所有数据,即对每行的数据进行运算得到一个数值,生成一个新的列。

  • 注意可能运算得到若干值(即返回值是一个tuple,如果是list也可以),此时可以通过设置参数return_type='expand'实现生成多个列,下面是一个例子:

    df = pandas.DataFrame(
    	'array1': [[1, 2, 3], [4, 5, 6], [7, 8, 9]]
    )
    
    print(df)
    print(df[['array1']].apply(lambda row: (row[0][0], row[0][1], row[0][2]), axis=1, result_type='expand'))
    
    # 输出结果
    """
          array1
    0  [1, 2, 3]
    1  [4, 5, 6]
    2  [7, 8, 9]
       0  1  2
    0  1  2  3
    1  4  5  6
    2  7  8  9
    """
    

axis=0时,apply中的apply_func的参数表示数据表一列的所有数据构成的一个pandas.Series,若对每列的数据进行运算:

  • 返回一个数值,则生成一个pandas.Series,比如取每列的最大值,平均数,众数:

    import pandas
    from collections import Counter
    df = pandas.DataFrame(
    	'array1': [1, 2, 3, 4],
    	'array2': [1, 4, 9, 16],
    	'array3': [1, 8, 27, 64],
    )
    print(df.apply(lambda column: column.max(), axis=0))
    
  • 返回若干数值,此时生成一个pandas.DataFrame,字段名不变,行数为返回值的数量,比如计算每列的移动平均:

    df = pandas.DataFrame(
    	'array1': [1, 2, 3, 4],
    	'array2': [1, 4, 9, 16],
    	'array3': [1, 8, 27, 64],
    )
    print(df.apply(lambda column: [(column[i] + column[i + 1]) / 2 for i in range(len(column) - 1)], axis=0))
    

2022-05-29

  • 然后莫名其妙地中午就回家了,门磁来得太快就像龙卷风,老老实实关个9天,至少能把CS224N肝完(目前进度6/19,项目开在我的GitHub),认真过一遍加上作业巩固的确还是很有用的,把很多模糊的点都搞清楚。
  • 佳明FR245到手,准备猛练,这几天就先用跑步机凑合,今天30分钟7km,感觉应该没有掉得太多,不过跑步机跟路跑差别还是挺大。
  • 晚上看到SXY在听《潇洒走一回》,是真喜欢听老歌,追新与怀旧形成了统一,人真是神奇的动物。

如何将预训练好的词嵌入融合到模型中继续训练?

比如embeddings是一个shape(30000, 50)的矩阵,那么我们可以直接在神经网络模型中定义:

self.embeddings = nn.Parameter(torch.tensor(embeddings))

然后编写从self.embeddings中取词向量的方法即可替代正常情况下的用法(即self.embeddings(x)):

def get_embeddings(self, w):
	# @param w (Tensor): input tensor of word indices (batch_size, n_features)
	# @return x (Tensor): tensor of embeddings for words represented in w (batch_size, n_features * embed_size)
	x = self.embeddings[w]
	x = x.view(w.size()[0], -1)
	return x

或许也可以用另一个方法,定义self.embeddings = nn.Embedding(30000, 50),然后初始化它的权重,即将embeddings赋值self.embeddings.weight,暂未验证这种方法的正确性。


2022-05-30

  • 在憋大招,准备六一腹泻式发布一大波博客。
  • 今天做核酸竟然让我下楼到路边做(目前还在第一个7天,第二个7天还没到)。实话说门磁装了跟没装也差不了多少,又没人来检查,完事还要我自己送回社区,那我直接把感应器撕下来跟信号源贴在一起,后台不就只能看到我的门是一直关着的。有多少人能做到单人单套房还绝对不出门呢?到头来不过是法不责众。
  • 所以说理想这种东西只能一个人去追求,一群人没有理想可言,上头做事太理想,下面就只能疲于应付,要么就屈尊下来走走看看,人不是机器,肉食者也做不了程序员

BLEU指数原理:
p n = ∑ ngram ∈ c min ⁡ ( max ⁡ i = 1 , 2 , . . . , n Count r i ( ngram ) , Count c ( ngram ) ) ∑ ngram ∈ c Count c ( ngram ) BP = 1 if len ( c ) ≥ len ( r ) exp ⁡ ( 1 − len ( r ) len ( c ) ) otherwise BLEU = BP × exp ⁡ ( ∑ n = 1 k λ n log ⁡ p n ) p_n=\\frac\\sum_\\textngram\\in c\\min\\left(\\max_i=1,2,...,n\\textCount_r_i(\\textngram),\\textCount_c(\\textngram)\\right)\\sum_\\textngram\\in c\\textCount_c(\\textngram)\\\\ \\textBP=\\left\\\\beginaligned &1&&\\textif len(c)\\ge\\textlen(r)\\\\ &\\exp\\left(1-\\frac\\textlen(r)\\textlen(c)\\right)&&\\textotherwise \\endaligned\\right.\\\\ \\textBLEU=\\textBP\\times \\exp\\left(\\sum_n=1^k\\lambda_n\\log p_n\\right) pn=ngramcCountc(ngram)ngramcmin(maxi=1,2,...,nCountri(ngram),Countc(ngram))BP= 1exp(1len(c)len(r))if len(c)len(r)otherwiseBLEU=BP×exp(n=1kλnlogpn)
其中 c c c是机器翻译得到的序列, r i r_i ri<

以上是关于完结囚生CYの备忘录(20220525-20220813)的主要内容,如果未能解决你的问题,请参考以下文章

完结囚生CYの备忘录(20221121-20230123)

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

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

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

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

连载囚生CYの备忘录(20220906-)