锐单电子商城 , 一站式电子元器件采购平台!
  • 电话:400-990-0325

【连载】囚生CYの备忘录

时间:2022-10-19 07:00:00 温度变送器温度超高km02h1重量变送器

序言

《白马非马》

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

——囚生

辗转时候,我还是回到这里继续写,希望这篇文章能写得更久,各种意义上。

最初,我决定坚持到底,因为我想看看上级什么时候愿意在这种荒谬的情况下做出让步。然而,我突然觉得用别人的错误来惩罚自己是不明智的,尤其是食品质量越来越不均衡,越来越不能满足日常培训的需要。如果大多数人坚定地选择留下来,他们将不可避免地对决策产生影响,但事与愿违。

匆匆忙忙,提前一天半买票,然后赶紧做好各种事情。虽然不愿意这样描述,但更像是一场比赛大逃亡。出站后,他被贴上各种标签进行集中控制。当车站工作人员喊着要快点离开时,即将进入集中营的囚犯们的视觉感受跳到了他们的心中。他们面前的老人拒绝加快速度。通过他们的背影,我们可以看到他们骨子里的固执。

幸运的是,走出封闭的建筑警戒线后,他松了一口气,两个月的高压状态得到了缓解。我还认识一个同学回到无锡,一起散步,有一种与活人打交道的新鲜感。这并不太糟糕。

最后是一些罔论

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

声明:这篇文章的观点只代表个人观点,而不是针对任何对象。不要猜测。本文将以备忘录的形式更新,直到字数达到文章可以发表的上限,以督促自己每天学习一些有用的新东西,鼓励你。


文章目录

  • 序言
    • 2022-05-25
    • 2022-05-26
    • 2022-05-27
    • 2022-05-28
    • 2022-05-29
    • 2022-05-30
    • 2022-05-31
    • 2022-06-01
    • 2022-06-02
    • 2022-06-03
    • 2022-06-04
    • 2022-06-05
    • 2022-06-06~2022-06-07
    • 2022-06-08
    • 2022-06-09~2022-06-11
    • 2022-06-12~2022-06-13
    • 2022-06-14~2022-06-15
    • 2022-06-16~2022-06-17
    • 2022-06-18~2022-06-19
    • 2022-06-20~2022-06-21
    • 2022-06-22
    • 2022-06-23~2022-06-24
    • 2022-06-25~2022-06-26
    • 2022-06-27~2022-06-29
    • 2022-06-30~2022-07-02
    • 2022-07-03~2022-07-04
    • 2022-07-05~2022-07-06
    • 2022-07-07
    • 2022-07-08~2022-07-10
    • 2022-07-11~2022-07-14
    • 2022-07-15~2022-07-17
    • 2022-07-18~2022-07-19
    • 2022-07-20~2022-07-25


2022-05-25

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

  • 一维情况

    假设有两种形状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])

  • 二维情况

    假设有两种形状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)

  • 三维情况

    假设有两种形状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_{\text{ngram}\in c}\min\left(\max_{i=1,2,...,n}\text{Count}_{r_i}(\text{ngram}),\text{Count}_{c}(\text{ngram})\right)}{\sum_{\text{ngram}\in c}\text{Count}_c(\text{ngram})}\\ \text{BP}=\left\{\begin{aligned} &1&&\text{if len}(c)\ge\text{len}(r)\\ &\exp\left(1-\frac{\text{len}(r)}{\text{len}(c)}\right)&&\text{otherwise} \end{aligned}\right.\\ \text{BLEU}=\text{BP}\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是标准翻译的序列(可能会有多个), len ( r ) \text{len}(r) len(r)是从 r i r_i ri中找一个长度最接近 c c c的序列(如果有多个长度最近的则选那个最短的), k k k是指定的最长的 ngram \text{ngram} ngram,一般取 4 4 4 λ i \lambda_i λi是一系列累和为 1 1 1的权重系数。

顺手照公式写了个BLEU指数的脚本:

# -*- coding: utf-8 -*-
# @author: caoyang
# @email: caoyang@163.sufe.edu.cn
# 计算BLEU指数

import numpy
from collections import Counter

def calc_bleu(nmt_translation, reference_translations, lambdas, k=4):
	# 权重系数的长度应当与ngram的最大长度相同
	assert len(lambdas) == k
	
	# 期望输入的是已经分好词的两个语句序列, 否则需要首先进行分词
	if isinstance(nmt_translation, str):
		nmt_translation = nmt_translation.split()
	for i in range(len(reference_translations)):
		if isinstance(reference_translations[i], str):
			reference_translations[i] = reference_transla

相关文章