添加链接
link之家
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接

阳历生日。今年因为年过得早的缘故,很多事情都相对提前了(比如情人节)。往年过生日的时候基本都还在家,所以一家子出去吃个饭也就罢了。今年承蒙凯爹厚爱,正好也有小半年没聚,他前天也刚正式拿到offer,于是狠狠地宰了他一顿哈哈(srds下个月他过生日还得还回去)。

难得跟人一逛老半天,从乳山四村到正大广场,吃完饭再回来,一路上交换见解与心得,从九点多一直到晚上六点多才走,凯爹的阅历让我受益颇多。我其实很羡慕凯爹这样的人,每一个能从二战走出来的都是勇士中的勇士,就是那种生活很有激情,并且目标明确,矢志不渝,这两个词我觉得是越来越难能可贵。

回来这些天除了泡实验室,每天还是至少会去遛五圈,前天浅浅地跑了5000米,其实也不是很吃力。说起来差不多停跑了有十天,相当致命,不过我发现因为这么多年来屡屡从低谷恢复训练,身体已经习惯了这种节奏,至少今年开始恢复的时候跑起来还是挺轻快的,虽然耐力明显很差,但也没有那么笨重。

初心难追,但是谁又愿意就如此屈服于生活呢?

20230320~20230321

  • 19号晚上回来后再起不能,这可能是这辈子以来最累的一天,出去找了点吃的回来就洗洗睡了,从11点睡到早上8点,完全是自然醒,舒服得要死,中午回来又补了2小时,原地满血复活。
  • 锡马净成绩1:42:07,跟预估差不多,半马人数8000,男子排名519,年龄段排名69,总排名601(算上女选手),排名差强人意,虽然比真实水平差了10分钟不止(稳进135,而且大概率能冲到130。142是三年前的水平)。
  • 约了sxy,三年了。再不约,可能就…,唉。

使用matplotlib制作mp4或gif动图:

from matplotlib import animation
from IPython.display import HTML
from matplotlib import pyplot as plt
def display_frames_to_video(frames):
    # figsize是以英寸为单位,dpi表示每英寸上多少个像素点
    plt.figure(figsize=(frames[0].shape[0] / 72, frames[0].shape[1] / 72), dpi=72) 
    plt.axis('off')
    patch = plt.imshow(frames[0])
    def animate(i):
        patch.set_data(frames[i])
    anim = animation.FuncAnimation(plt.gcf(), animate, frames=range(len(frames)), interval=50)
    # anim.save('cartpole.mp4')
    anim.save('cartpole.gif', writer='imagemagick')
    HTML(anim.to_jshtml())
display_frames_to_video(frames)

解释:fig是一开始定义好的图形对象(如plt.gcf()),关键是animate函数,这里的frames是一个列表,每个元素是一张RGB图像张量,这里只是简单的把每一帧给扔进patch,也有在一张静态图上不断移动一个点的写法:

import matplotlib.pyplot as plt
%matplotlib inline
line, = ax.plot([0.5], [2.5], marker='o', color='g', markersize=60)
from matplotlib import animation
from IPython.display import HTML
def init():
    line.set_data([], [])
    return (line, )
def animate(i):
    state = state_history[i]
    # 根据state确定点的移动坐标
    x = state % 3 + 0.5 
    y = 2.5 - state // 3
    line.set_data(x, y)
# 一秒5帧
anim = animation.FuncAnimation(fig, animate, init_func=init, 
                               frames=len(state_history), interval=200, repeat=False)
anim.save('maze_0.gif', writer='imagemagick')
HTML(anim.to_jshtml())

HTML可以在notebook里做出类似播放器的效果。

20230322

  • 阴雨绵绵,让人提不起兴致。下午四点多去操场准备养生一会儿。发现东哥居然在练3000米(五月底有个上海市教工运动会),这不趁机给东哥上个强度,穿牛仔裤也得给他好好拿捏一下。
  • 东哥目标进14分钟,带他跑出13’09",最后100米轻松绝杀。对我来说只是热身,而对东哥已是极限,只是可惜忘了给东哥来几张表情包。不过他下周还想进13分钟,机会有的是(ಡωಡ)。就怕到时候例训公报私仇,12×400米间歇给我直接干废哈哈。

最近发现一个很强的UP,五道口纳什,CSDN也有博客,全栈算工,真的是太全面了,啥都会,而且大多数面都要比我要精好多,所以准备把他的vlog全部学一遍,真的很有用。

使用meshgrid方法可以实现3D作图的坐标轴控制:

import numpy as np
import matplotlib.pyplot as plt
from matplotlib import cm
xs, ys = np.meshgrid(np.arange(-2, 2.01, .01), np.arange(-2, 2.01, .01))
zs = np.exp(-(xs**2+ys**2))
# xs: 401 × 401
# ys: 401 × 401
zs = np.exp(-(xs**2+ys**2)) # zs: 401 × 401
fig = plt.figure(figsize=(16, 12))
ax = fig.add_subplot(111, projection='3d')
surface = ax.plot_surface(xs, ys, zs, cmap=cm.jet)
fig.colorbar(surface)

另一种在jupyter里可交互的作图方式:

from mpl_toolkits.mplot3d import Axes3D
%matplotlib notebook
fig = plt.figure()




    

ax = Axes3D(fig)
xs, ys = np.meshgrid(np.arange(-2, 2.01, .01), np.arange(-2, 2.01, .01))
# creating the plot
surface = ax.plot_surface(xs, ys, zs, color='green', cmap=plt.get_cmap('rainbow'))
# setting title and labels
ax.set_title("3D plot")
ax.set_xlabel('x-axis')
ax.set_ylabel('y-axis')
ax.set_zlabel('z-axis')
fig.colorbar(surface)
# displaying the plot
plt.show()

20230323

  • 晚上例训。3000米乳酸阈跑(with嘉伟,11分整,中途要停一圈,这已经是我的极限了,自测3000米最快能到11’30",今天第一个1000米就被带到3’30",力不能及)+ 3000米放松跑(with东哥,13’39",东哥说他五年前能跑到9’08",超二级水平,太恐怖了,没想到现在垮得这么厉害)+ 2000米追逐+ 2000米冷身,外加4组箭步跳和蛙跳。
  • 锡马回来后四天在循序渐进地恢复,现在左胯仍抽痛,用力压会疼,其他地方都已经完全恢复,最近休息得很好,虽然没有拉强度,但是应该状态已经恢复到巅峰了,下周队内会有一次体测,争取把5000米再次跑进20分钟。
  • 嘉伟周日要去芜湖跑半马,本来卢星雨是芜湖人,可惜她也垮得很,说可以租个儿子去跑亲子欢乐跑,TM笑死。
  • 看了一下栾云平的无锡专场,便宜的位置都卖光了,剩余最低580,90分钟一场确实挺贵滴,小园子倒是便宜得多。因为我一直在想要不要送个生日礼物,或许搞个票是不错的选择,但莫名感觉sxy会不会已非单身。害,庸人自扰。

制作2048的环境,以及pygame渲染:

# -*- coding: utf-8 -*-
# @author : caoyang
# @email: caoyang@163.sufe.edu.cn
import numpy
import random
from copy import deepcopy
class Env2048:
	initialize_proba_for_2 = .9	# Each round with some probability to generate tile 2 at random position
	n_initial_tile = 2			# The number of initial tiles in the start
	score = 0					# Log the game score
	actions = list(range(4))	# {0, 1, 2, 3} -> {U, R, D, L}
	def __init__(self, args, is_debug=False):
		self.args = deepcopy(args)
		self.is_debug = is_debug
		self.reset()
	# Restart game
	def reset(self):
		self.grid = numpy.zeros((self.args.order, self.args.order)).astype(numpy.int16)
		for _ in range(2):
			self.add_tile()
		self.mode = 'run'
	# Step to next state with some action
	def step(self, action):
		if self.mode in ['over', 'win']:
			return
		grid = self.grid.copy() if self.is_debug else self.grid
		score = 0
		if action == 0:
			# Upward 0
			for i in range(self.args.order):
				score += self.merge_bar(bar=grid[:, i])
		elif action == 1:
			# Rightwards 1
			for i in range(self.args.order):
				score += self.merge_bar(bar=grid[i, ::-1])
		elif action == 2:
			# Downward 2
			for i in range(self.args.order):
				score += self.merge_bar(bar=grid[::-1, i])
		elif action == 3:
			# Leftwards 3
			for i in range(self.args.order):
				score += self.merge_bar(bar=grid[i, :])
		if self.is_over():
			self.mode = 'over'
		if self.is_win():
			self.mode = 'win'
		self.add_tile()
		self.score += score
		return score
	# Sample the position of some empty tile 
	def sample_available_position(self):
		available_positions = list()
		for x in range(self.args.order):
			for y in range(self.args.order):
				if self.grid[y, x] == 0:
					available_positions.append((y, x))
		# assert available_positions, f'There is no empty tiles in grid: {self.grid}'
		return random.choice(available_positions) if available_positions else None
	# Randomly add 1 tile to grid
	def add_tile(self):
		position = self.sample_available_position()
		if position is not None:
			y, x = position
			self.grid[y, x] = 2 if random.random() < self.initialize_proba_for_2 else 4
	# Move one row or one column for merging
	def merge_bar(self, bar):
		score = 0
		bar_length = len(bar)
		for i in range(bar_length - 1):
			if bar[i] == 0:
				for j in range(i + 1, bar_length):
					if not bar[j] == 0:
						bar[i]




    
 = bar[j]
						bar[j] = 0
						score += 1
						break
			if bar[i] == 0:
				break
			for j in range(i + 1, bar_length):
				if bar[j] == bar[i]:
					bar[i] += bar[j]
					score += bar[j]
					bar[j] = 0
					break
				if not bar[j] == 0:
					break
		return score
	# Whether is game over
	def is_over(self):
		if 0 in self.grid:
			# There exist some empty tiles in grid
			return False
		for y in range(self.args.order - 1):
			for x in range(self.args.order - 1):
				# There exist some ways to merge tiles
				if self.grid[y][x] == self.grid[y][x + 1] or self.grid[y][x] == self.grid[y + 1][x]:
					return False
		return True
	# Whether is game wins
	def is_win(self):
		return self.args.game_goal in self.grid
	# Stringize
	def __str__(self):
		string = '====================\n'
		for row in self.grid:
			string += '-' * (5 * self.args.order + 1) + '\n'
			for e in row:
				string += '|{:4d}'.format(int(e))
			string += '|\n'
		string += '-' * (5 * self.args.order + 1) + '\n'
		string += '==================\n'
		return string

20230324~20230325

  • 春寒料峭,昨天状态又极度低迷,感觉这几天衣服穿太少给冻着了,有点发烧的征兆,早早睡了一觉又基本恢复过来了。
  • 下午例训,全员8×400米间歇,状态不错,能1’15"~1’20"的pace坚持到底,没有不适,最后两组甚至跑到前三,仅次于杨申宇和宋镇均(不得不说宋镇均的话一个标点不能信,第3组跑完跟我说上头了,让我站他前面出发,然后每组都超我,一点不给老学长面子)。再跟队练三周到扬马结束,至少进个135,了却这桩心愿。
  • 找工作确是玄学,尤其是近两年,但无论如何,sxy都确是足够优秀了,实话令人艳羡不已,能去中金真的已是天花板。与三年前很像,不过今天我是听众,熟悉的清澈,褪去了些青涩,多了些岁月的蹉跎,以及恍惚间的落差。好多话没能说出口,也不知道两年后我会何去何从,以后还能否再见。然,人生能有这么一段三年多的邂逅,cy,你也该知足了罢。

2048蒙特卡洛代理,利用两个经典的指标进行:

class MonteCarloAgent(BaseAgent):
	gamma = 2.8
	def __init__(self, args):
		super(MonteCarloAgent, self).__init__(args)
		self.env = Env2048(self.args, is_debug=False)
	# Generate the next action given grid state
	def generate_next_action(self, grid):
		action_grades = []
		n_empty_tiles = self.count_empty_tiles(grid)
		if n_empty_tiles >= self.args.order ** 2 / 3:
			# There exist so many empty tiles that we can act randomly
			if self.args.gather_to_corner == 'ul':
				return random.choice([0, 3]), {'grade': 0}
			elif self.args.gather_to_corner == 'ur':
				return random.choice([0, 1]), {'grade': 0}
			elif self.args.gather_to_corner == 'dl':
				return random.choice([2, 3]), {'grade': 0}
			elif self.args.gather_to_corner == 'dr':
				return random.choice([1, 2]), {'grade': 0}
		# Simulate
		n_simulate = min(max(n_empty_tiles ** 2, 20), 40)
		for action_list in itertools.product(self.env.actions, repeat=self.args.montecarlo_search_depth):
			candidate_grades = []
			for _ in range(n_simulate):
				grid_final = self.generate_simulated_grid(grid, action_list)
				candidate_grades.append(self.grade_grid(grid_final))
			action_grades.append([action_list, min(candidate_grades)])
		action_grades = sorted(action_grades, key=(lambda x: [x[1]]))
		for action_list, grade in action_grades[::-1]:
			self.env.grid = grid.copy()
			if not self.env.step(action_list[0]) == 0




    
:
				# Return the first action in sorted actions list by grade
				return action_list[0], {'grade': grade / n_simulate}
		# Revert
		self.env.grid = grid.copy()
		return action_grades[-1][0][0], {'grade': action_grades[-1][1] / n_simulate}
	# Generate the final grid given a grid and a list of simulated actions
	def generate_simulated_grid(self, grid, action_list):
		env = Env2048(self.args, is_debug=False)
		env.grid = grid.copy()
		for action in action_list:
			env.step(action)
			env.add_tile()
		return env.grid
	# Grade the current grid 
	def grade_grid(self, grid):
		return self.grade_algorithm_1(grid) + self.gamma * self.grade_algorithm_2(grid)
	# Count the number of empty tiles in grid
	def count_empty_tiles(self, grid):
		return numpy.sum(grid == 0)

20230326~20230327

  • 昨日休整,去小姨家养了波胃。前晚肚子不适,不知是九鼎轩东西不干净还是一回来就跑高强度间歇的缘故,总之就是不舒服。陈嘉伟首半马顺利完赛,净成绩1:28:26,配速4’11",这还不是完全发挥出来的水平。半马跟嘉伟的差距要小一些,配速差大概在15秒。
  • 注册openai账号,打不过就加入呗,openai还不给china和russia提供服务,买了个巴西的虚拟号码才验证通过,梯子又不稳,凌晨搞到一点才弄好。
  • 主要是近半个月很多大模型的api都开放了,所以上周主要在追踪前沿,如提示工程,图像的diffusion之类的。其实prompt很早就有提出,那时候还以为只是简单的补全,现在看来真的是坐井观天。LLM和Prompt,这是方法论和工业应用的双重革新,有预感大变革真的要来了。
  • 下午晃了十圈,碰到宋镇均在自测5000米,结果这货少跑了一圈,18’32",亏我还长袖长裤、而且没热身就带了他两段。可惜明天临时要汇报,估计要错过队内测试,这么好的状态多想能重开一次20分大关。(说起来一年半前还打开一次20分钟,自己这么久就一点长进都没有,好菜)。

LLM与提示工程之遐想

其实现在看来提示学习的确是革新了传统的预训练方法,那些传统的预训练模型可能很快就要被淘汰,GPT崛起说明预训练根本不需要搞那么多花里胡哨地操作,做自回归就完事了,有种数学里常说的朴素简洁的美。

关于提示,几乎已经可以覆盖所有的NLP任务,虽说现在提示工程看似只是在对一个黑盒子进行不断地试错,没有什么理论依据可言,之前王英林坚持不肯在本子里写提示学习,就是觉得这种东西没有什么科研价值,就一群人在那儿写模板喂给模型,而且很多时候还需要人类来对模型的输出进行反馈。但是从另一个角度来看,提示工程有点类似在对人脑的思维逻辑进行解析,事实上我们也没有办法完全弄明白人脑的运行逻辑,所以提示工程里有很多提示构建的思路,比如思维链(CoT),ReAct,以及生成外部知识模板,甚至将逻辑用代码形式进行提示,其实都是在帮助模型学习推理的能力,但是这种推理能力并不是结构化的,它依然是非结构化的文本组成,你很难说模型到底学习到的是推理能力,还是只是以文本形式呈现的推理过程,抑或说本身推理确实也可以是非结构化的呢,只是人类更偏爱使用结构化的推理形式而已?

这波冲击对NLP是及其巨大,但是随着多模态提示的发展,图像领域可以预见到的很快也会受到冲击,其实diffusion作为一种MC也可以理解是一种自回归,这和文本预训练上的思路是一致的。其实我一开始以为diffusion是以像素点级别进行自回归扩散的,当时觉得这个思路好神奇,但是并不是这么做的,为什么不是这么做呢?比如对于图像补全,感觉上以像素点进行自回归扩散更合理,OR里面会用nuclear norm来进行优化实现图像补全,本身也是基于熵减的思想。

openai补全接口调用:

import openai
import os
import Ipython
from langchain.llms import OpenAI
from dotenv import load_dotenv
load_dotenv()
openai.api_key = os.getenv("OPENAI_KEY")
os.environ["OPENAI_API_KEY"] = os.getenv("OPENAI_KEY")
os.environ["SERPART_API_KEY"] = os.getenv("SERPART_API_KEY")
def set_open_params(model='text-davinci-003',
                    temperature=.7,
                    max_tokens=256,
                    top_p=1,
                    frequency_penalty=0,
                    presence_penalty=0):
    openai_params = {}
    openai_params['model'] = model
    openai_params['temperature'] = temperature
    openai_params['max_tokens'] = max_tokens
    openai_params['top_p'] = top_p
    openai_params['frequency_penalty'] = frequency_penalty
    openai_params['presence_penalty'] = presence_penalty
    return openai_params
def get_completion(params, prompt):
    response = openai.Completion.create(engine=params['model'], 
                                        prompt=prompt,
                                        temperature=params['temperature'],
                                        max_tokens=params['max_tokens'],
                                        top_p=params['top_p'],
                                        frequency_penalty-params['frequency_penalty'],
                                        presence_penalty-params['presence_penalty'])

20230328

  • 下午组会,错过训练(事后碰到谢震宇问了下,其实东哥根本没来,就没咋练,还好还好,主要状态是挺好,练不了有点可惜)。两天不到把锡马回来一周多看的东西整出来并讲了一遍,颇有所得,从gpt1到gpt4,再到提示工程的技术,以及这个月刚刚开放的各种OpenAI接口,做了一回LLM和AIGC的传教者。从我的角度来说,LLM和AIGC的到来确是令人激动的事情。虽然我们还不能直接无代价的接触到LLM,但只是摸到一点皮毛也足以令人兴奋。
  • 会后跟黄名媛回实验楼,在看暑期实习,跟我说加了颜烨,然后这B居然让她去投开发岗,是真TM离谱,颜烨这是人做出来的事儿?
  • 21级的时候就来了一个黄名媛,我过了差不多快一年才看到真人。今年进了4个,而且居然有个直博新生,我都以为王英林要退休了,居然还要带博士,这可至少五年,到时候都快70岁。
  • 晚上强行想认真跑会儿,之后可能要连着下雨。虽然下午感觉很好,但是到晚上毕竟还是太累了,没睡午觉状态又差,奔着10km去跑结果不到2km就报销了,又断断续续补到5km,说起来还是在扬马备赛期,不论配速,每天还是要把跑量补足。

LLM与提示工程之遐想(二)

提示工程指南:GitHub高星项目

如果说GPT4真就只靠无监督的自回归训练+多任务微调那确实太夸张了,它的训练过程中一定有很多细节没有公开,否则很难想象text-to-SQL以及代码生成等公认的高难度NLP任务就这么被一个说不清道不明的in-context learning一举拿下了。以Text-to-SQL著名的Spider挑战任务为例,上个月刚提出的SOTA模型也超过不了80%的正确率,根本不足以达到应用范畴,但是事实上这也不能在GPT4中测试,因为context太长,除非把Spider的整个数据库扔进去。

即便如此,正如昨天写到的那样,以提示为起点,自回归为方法的LLM&AIGC新方法,抛却了一切花里胡哨的结构化操作,确是一种简单朴素的美。以前总是认为规则、推理是需要用结构化的方式进行表达,比如一阶规则,现在看来自然语言几乎可以概括一切规则。不管你信不信这是不是推理能力,反正LLM就是能推出来。

最后推荐几个图像领域的,从GPT4开始已经可以进行提示生图的操作了,当然这些技术半年前就已经很成熟了,AI绘图早已不是,这么看来,图像还是要比文本要容易一些。我以前也是这么认为,因为文本的精确性要求更高,图像还是有一定容错的。https://civitai.comDiffusion公式推导

Image Caption(调用Blip模型):

import torch
from transformers import BlipProcessor, BlipForConditionalGeneration
from PIL import Image
device = 'cuda:0'
processor = BlipProcessor.from_pretrained("Salesforce/blip-image-captioning-base")
model = BlipForConditionalGeneration.from_pretrained("Salesforce/blip-image-captioning-base", torch_dtype=torch.float16).to(device)
# processor forward,模型的输入需要经过processor进行预处理
img_inputs = processor([Image.open('./flickr8r-samples/33108590_d685bfe51c.jpg'), 
                        Image.open('./flickr8r-samples/10815824_2997e03d76.jpg')], 
                       return_tensors='pt').to(device, torch.float16)
print(img_inputs['pixel_values'].shape)
out = model.generate(**img_inputs) # 输出结果是一个LongTensor
# 需要用processor解码
# processor.tokenizer.convert_ids_to_tokens(out[0])
captions = processor.decode(out[0], skip_special_tokens=True)
print(captions)
captions = processor.decode(out[1], skip_special_tokens=True)
print(captions)

20230329

  • 开始面实习,早上做阿里的行测,智商严重受辱,拿各种小学数学应用,阅读理解还有离谱的图形规律来恶心人。后晚要电面,因为是数算岗,跟近期看的内容不搭嘎,又得刷算法题准备机考,以及把之前写的pyspark和hadoop笔记拿出来复习。就是那种,想、又不想实习的矛盾感。
  • 晚饭后准备去操场散会儿步,路上碰见东哥刚练完,告诉我本来上周六3000米已经跑到12’49",结果三天不练又被打回原形。然后卢星雨和丁古丽也在慢跑,想想我也有好几天没有认真跑了,之后又要下雨,晚上状态虽低迷,还是换了衣服鞋子上场拉一拉强度,4000米用时16’04",配速4’01",马马虎虎。
  • 说起来,这学期若不是有嘉伟带,我很难两周就重回巅峰。非例训时间里,我一个人训练很难上大强度。以前习惯独自训练,一周也能跑出7个高质量的万米,现在变得越来越依赖随队氛围,就是那种被人认同也认同别人的氛围。然,越是依赖,越是遗憾,早晚会离开这样的欢乐与纯粹。聚少离多,能陪伴一生的人和物是何等的无价珍宝呢。

Legion笔记本,摄像头灯亮,但是显示黑屏问题解决:

摄像头的盖子没掀开阿,如果你发现摄像头最中间是一个红点,那就是被盖住了,看看摄像头上方有个很不起眼的像是滑槽(可以左右滑)的东西,往右边一滑就开了。TM下午搞了半小时,还以为是摄像头驱动坏了,差点准备卸了驱动重装,真是服了。

就特别搞,看网上说联想笔记本摄像头是有物理开关的,我还在想是不是右边那个小孔是开关,用针捅了半天旁边兄弟跟我说那应该是麦克风,我???

20230330

  • 晚上例训,跟嘉伟3’54"配速上3000米,我已力竭,于是被嘉伟无情嘲讽,他表示根本没尽兴,才3k就不行了?于是被迫补2组2000米间歇(分别偷懒了大半圈,真心跟不动),休息后8组×32个箭步跳,最后补1组2000米变速。练到胃的一晚,舒服得要死。可是明晚要面,题还没刷完,刷题真是浪费生命,昨晚刷到11点半才回寝,真是无语透顶了,今晚绝不熬夜。
  • sxy去了南德,180块vip豪华一排座,属实慕了。讲道理小园子票价还是很亲民的,快乐一天总归比去影院看烂片舒服。
  • 我最近又认识了几个跑的还不错的人,大二金融一个(这个要比我强,感觉4分配不在话下),还有今晚认识的一个大四经济(这个应该水平跟我差不多)。其实财大也不算小,想想总归是有些能跑的人,只是缺少号召力把这些人都集中起来,完善现在的训练氛围,长跑水平不见得比交大同济差,可惜我大概是看不到了。

nowcoder个人刷下来链表里感觉最难的是BM5(归并排序K个单链表),还有一些算法说实话思路跟小学奥数题一样,能不能来点不用取巧的算法题,比如什么找两个单链表第一个重合的元素那题,双指针的思路也太离谱了,没见过原题绝对不可能短时间想出来,跟脑筋急转弯似的。

import sys
#设置递归深度
sys.setrecursionlimit(100000) 
class Solution:
    #两个有序链表合并函数
    def Merge2(self, pHead1: ListNode, pHead2: ListNode) -> ListNode: 
        #一个已经为空了,直接返回另一个
        if pHead1 == None: 
            return pHead2
        if pHead2 == None:
            return pHead1
        #加一个表头
        head = ListNode(0) 
        cur = head
        #两个链表都要不为空
        while pHead1 and pHead2: 
            #取较小值的节点
            if pHead1.val <= pHead2.val: 
                cur.next = pHead1
                #只移动取值的指针
                pHead1 = pHead1.next 
            else:
                cur.next = pHead2
                #只移动取值的指针
                pHead2 = pHead2.next 
            #指针后移
            cur = cur.next 
        #哪个链表还有剩,直接连在后面
        if pHead1: 
            cur.next = pHead1
        else:
            cur.next = pHead2
        #返回值去掉表头
        return head.next 
    #划分合并区间函数
    def divideMerge(self, lists: List[ListNode], left: int, right: int) -> ListNode:         
        if left > right :
            return None
        #从中间分成两段,再将合并好的两段合并
        mid = (int)((left + right) / 2) 
        return self.Merge2(self.divideMerge(lists, left, mid), self.divideMerge(lists, mid + 1, right))
    def mergeKLists(self , lists: List[ListNode]) -> ListNode:
        #k个链表归并排序
        return self.divideMerge(lists, 0, len(lists) - 1) 

20230331

  • 晚7点阿里面试,面了两个小时,从统计回归问到机器学习,从逻辑回归问到Transformer,又现场考了四道代码题,最后考官表示对我的表现是满意的,并希望很希望我能加入他们的团队。
  • 我只准备了两天(而且根本没看这些基础知识,全TM在刷垃圾算法题),硬是靠坚实的基础(臭不要脸一回)全都接下来,可惜sql完全没看,最后一道sql直接缴械,想sql还是在杉数时做的了。其实也有面试官跟我可能熟悉的领域非常相近的缘故,几乎所有问题我都是了解的,就算不知道我也能猜出个大概。
  • 时隔三年,又激起了我去实习的欲望。原因这已经很贴近我理想中的工作了,我可能还是不能去做那种尖端产品的开发,太难,而且不确定性太大,保不准哪天就被结构性调整,而且有一说一,这一块国内确实很难追上,因为氛围不对。OpenAI出身是非盈利性组织,那是真正出于爱好和钻研才集合到的一批最炽热的人,方有如今的成就,而工业永远是以利益为目标的,所以永远出现不了OpenAI这种品级的机构。
  • 但是数算支持带些深度学习技巧对我来说要容易得多,而且是公司必要且不可或缺的。考官说他对杉数很熟悉,也是看重了我在杉数的那七个多月的经历,团队里也有以前在杉数工作过的人,而我也确实很怀念三年的杉数,那是一群年轻人有福同享,有难同当,没有勾心斗角的时光。
  • 然,有得必有失,一天400拿的是很舒服,但我也会失去大部分的自由。我不喜欢被束缚的生活,晚饭后在操场晃悠时又看到卢星雨和丁古丽在跑5000米,而且居然有一个比卢星雨跑得还快的女生,好强,我还以为lxy已经是天花板了,这种充满活力的感觉真好。停三年实习,跑三年步;逃离三年现实,追逐三年梦想,再看自己早已不再年轻,马上就是奔三的人,却仍是孩童样,这是见sxy那天落差感来源,我觉得她已经远比三年前自信成熟了,也许这才是正常的样子吧。

阿里算法岗一面面经回忆(不全):

  • 多元线性回归模型中的常用检验?(我答:变量显著性检验、方程显著性检验、异方差检验、多重共线性检验,从几个古典假设入手)

  • 多元线性回归模型的OLS估计的解释?(我只回答了矩估计和正规方程组,考官表示还有最大似然和几何角度的解释)

  • 对可决系数R方理解?

  • 机器学习方法概述?(从逻辑回归到各种树)

  • 树模型,GBDT和随机森林的区别(我答Boosting和Bagging,串行和并行)。

  • xgboost的分裂原理?(这个我真不清楚,但是我觉得是可以调的,那些ID3, ID4.5, CART之类的最大熵算法),调参(最大树深,最多叶子,树的数量)及具体场景。

  • xgboost本身自带有避免过拟合的机制,是什么?(这个我也不清楚,我只知道调参,后来好像也搜不到,有知道的吗)

  • lightgbm与xgboost的比较(更快,尤其处理大数据),为什么?(这个我不清楚,但是立刻猜到了应该是采样)

  • 这里还问了一个,用树模型是否可以实现单调性?(即x增,y增这种性质,其实我也没太理解,但是肯定是分枝上做一些界限的限制吧)

  • 介绍RNN?(略)

  • 介绍LSTM中的门,及其为什么这么取名(这个当时我还真忘了,但是刚好开着浏览器就搜了一下三个门,其实就三个式子,还是要稍微熟悉一下,别忘了GRU,下次可能就是这个)

  • RNN的梯度消失与梯度爆炸解释(消失是其中一次是零,爆炸则是太长),及出现该情况时训练会发生什么(梯度消失则不更新,爆炸则乱更新)

  • LSTM的反向传播有什么技巧么?(这个我觉得LSTM其实参数并不多,因为每个Cell是共享参数的,所以我其实不太清楚他想问什么,可能是叠加吧我觉得,大概)

  • Transformer概述(略)

  • Transformer用于时序预测,如果其中有一段没有数据(比如过年期间没有销量),是否可以直接MASK(在文本里面是可以直接MASK的,这很常见,但是时序有特殊性,但是我不能很专业的讲明白,可能要再想清楚点儿)。

  • 问了我一些因果推断的东西,因为我在简历里写了,这刚好是我熟悉的,就不多说了。

  • 实时机考题(四道):

    • pandas题,一个dataframe,A,B,C三个列,现在生成第4个列D,取值B当A=1,取值C当A=0,要求高效(比如处理100万行)
      思路,这个给我第一眼我是觉得应该用apply写:
      df['D'] = df[['A', 'B', 'C']].apply(lambda x: x[1] if x[0] == 1 else x[2])
      
      但是要求高效的话,立刻反应过来应该是用向量解:
      df['D'] = (df['A'] == 1) * df['B'] + (df['A'] == 0) * df['C']
      
    • 一道简单的哈希表,从list里找到两个相加为target的数的下标,刚好昨天才看过,我诚实地告诉他我刚看过,他也很客气,说就不给我换动态规划了(笑死)。
    • 实现Kmeans,封装成类,并且可以继承修改其中的distance算法,这个也不算难,这里额外问了python能否多继承,Java和C++能否多继承的问题。
    • 从数据表中筛选出今天的价格比昨天高5%的SKUID,使用SQL/Hive/Progress(我很老实的承认sql很长时间不写了,确实不会写这种比较复杂的,但是pandas我一定会写…)
  • 最后考官问我还想问他什么,我问了一下他们部门的工作和日常,越发觉得很适合我,我本来跟考官说我很佛系的,过不了也无所谓,现在我又很想进了。考官让好好准备笔试,别考得太烂。

20230401

  • 下午队内测试,今天只测立定跳远、立定三级跳、跳远、50米和400米,虽然都是短跨项目,但也顺带试试自己练了这么久,相较本科到底是否提升。结果立定跳居然都不到2米5(本科最远还是能上2米5);立定三级跳完全没练过,所以只能跳6米4,差点进不了坑,跳远倒还行,跳到4米7。跳远考验的是大腿爆发力,显然我是不行的,前两项都是男生中倒二(宋镇均全部垫底,感觉他找不到技巧,立定2米35,三级跳6米17,不过练长跑的爆发力的确是比不过练短跑的),跳远成绩还行,应该是前5。
  • 说到底长跑练多了之后肌肉僵硬,弹性不足,确实不适合做这种跳跃项目,陈嘉伟测下来成绩也不好。
  • 50米真的拉垮,本科最快还能跑到7秒2,好久不练短跑都不会跑了。主要是不会起跑,如果是慢慢加上去就很符合平时的感觉,但是一下子想把速度加上去就完全找不到步调,然后就保持不了前脚掌跑,居然用后跟跑法冲了50米,而且路线都跑歪了,7秒6,真是废的真实,我觉得自己水平肯定不止于此,但也懒得再测一次了,因为其他人基本都能跑进7秒,再跑一次估计也就7秒整左右的水平。
  • 最后400米1’09",意料之中,估计是在70秒左右的水平,还是比较满意的,差不多比一年前提升5秒多,前面冲太猛,后程掉的太厉害了。

关于昨天提到的xgboost自带防止过拟合的机制,我想起来了,他说的是正则项,具体大概是对树深合maxleaf进行惩罚。

重拾SQL: