PyTorch collate_fn and Python zip function
Part of the article is generated by [ChatGPT]
collate_fn
This post records about the collate_fn
from torch.util.data.DataLoader
and the python built-in function zip
.
Each batch, the dataloader collects batch_size
number of items. They are picked from the dataset one by one. So currently, the batch data is [(data1, target1), (data2, target2), ..., (dataN, targetN)]
.
The default collate_fn
would change it into [torch.tensor([data1, data2, ..., dataN]), torch.tensor([target1, target2, ..., targetN])]
.
However, in some NLP tasks, the data is not in the same length. So we need to apply torch.nn.utils.rnn.pad_sequence
to make each data same length (usually the maximum length in this batch). A typical implementation is:
1 | def collate_fn_train(batch): |
zip and *
- What does the
zip
do in the above function?
The zip()
function in Python is a built-in function that takes one or more iterables (such as lists, tuples, or strings) and “zips” them together, returning an iterator of tuples where the i-th tuple contains the i-th element from each of the input iterables.
1 | a = [1, 2, 3] |
- What is the
*
?
In Python, the asterisk (*) symbol can be used to unpack iterables like lists or tuples. When used in this way, the asterisk is sometimes called the “splat” operator or the “unpacking” operator. The unpacking operator is used to extract the individual elements from an iterable and assign them to separate variables.
1 | my_list = [1, 2, 3] |
- So, what is the
x, y = zip(*batch)
?
First, batch
is [(data1, target1), (data2, target2), ..., (dataN, targetN)]
.
*batch
would unpack the outmost list, to be zip((data1, target1), (data2, target2), ..., (dataN, targetN))
. The result would be two tuples, [data1, data2, ..., dataN]
and [target1, target2, ..., targetN]
. The former one is assigned to x
and the other is assigned to y
.
In this way, we get separate data structure, that contains all data
and target
respectively.
Convert Python Dictionary to Source Code of Latex and Markdown
The code is generated by [ChatGPT].
Here are two common functions, that can convert the python built-in dictionary into the format of latex/markdown unnumbered list, so that we can copy it into the latex/markdown. Example can be:
The input python dictionary is:
1 | my_dict = { |
The result for markdown is:
1 | - fruits |
and result for LaTeX is:
1 | \item fruits |
Function explanation: it is as simple as it shows. We use the recursion strategy here. When we are going to print a sub-dictionary, we recursively call the function, with more (two) spaces indented.
Dict to latex unnumbered list
1 | def dict_to_latex(d, level=0): |
Note that we should avoid the _
in our string. So we need first convert it into escape character, \_
.
The result of the string should be wrapped by a \begin{itemize} \end{itemize}
.
Dict to markdown unnumbered list
1 | def dict_to_markdown(d, level=0): |
C/C++ 复杂类型声明规则(2)-识读const关键字
“C/C++ 复杂类型声明规则” 将分为两节。第一节介绍螺旋法则声明规范,第二节介绍const的修饰关系。
本节主要解决以下问题:
1 | const int *a; // a可变嘛? *a可变嘛? |
这两节内容,我都尝试以一种不用死记硬背,而是理解的方式去掌握。
本文参考自【初中生也能看懂的C/C++类型声明规则教学,很简单的!】 https://www.bilibili.com/video/BV1mB4y1L7HB/ 。里面通过一些例子介绍了螺旋法则和对const关键词的判读。我将在此基础上加上我对其的解释,使其变得更加通俗易懂。
基本解决思路:const 只修饰右边最近的东西。
例如const r
, 说明r
这个变量是const的,不能动。const *r
,意为const (*r)
,说明*r
,r指向的东西,是const的。r自身可以变化。
再例如,const int r
, 说明这个int是const的。这个整数是常量。r
是一个整型常量。
举一些例子:
例子1
1 | int const a1 = 5; |
在这里,两个其实是等价的。对于第一个,a1
被const修饰了,所以a1
不能变。a1
是一个整型变量。所以连起来,a1
是一个常量整型变量。对于第二个,可以理解成a2
是一个const int,a2
是一个常量整型变量。
所以,不同的声明形式,意义可能相同。
例子2
1 | int const *p1 = &a1; |
在这里,两个其实也是等价的。对于第一个,*p1
被const修饰了,所以*p1
不能变。即p1
指向的是一个整型常量。对于第二个,可以理解成p2
指向一个const int,p2
指向的是一个常量整型变量。对于这两个来说,p1
p2
自己可以变,但是他们指向的不能变。
一个声明里的多个const,意义可能相同。例如:
1 | const int const *p3 |
这个例子里虽然有两个const,但其实还是只修饰了一个*p3
。p3
自身没有被const修饰,可以变。
例子3
1 | int *const r2; |
在这里,r2
直接被const修饰,所以r2
不能变。r2
指向一个int,那个int没有额外修饰,所以那个int是可以变的。总之,r2
是不能变的,但是r2
指向的int是可以变的。
例子4
1 | const int *const r3; |
在这里,r3
直接被const修饰,所以r3
不能变。r3
指向一个const int,那个int没有额外修饰,所以那个int是可以变的。总之,r3
是不能变的,r3
指向的int也不可以变的。
例子5
1 | const int **r5; |
r5
指向一个指向int的指针。这个被指向的指针指向的int是被const所修饰的。所以r5
可以变,r5
指向的那个(指向int的指针)也是可以变的,但是r5
指向的指针指向的int没得变。
例子6
1 | int const * const * const r6; |
上面那个例子的升级版。r6
指向一个指向int的指针。r6
被const修饰,r6
不能变。r6
指向的(指向int的指针)被const修饰,即*r6
不能变。r6
指向的指针指向的int,**r6
也被const修饰,也不能变。
C/C++ 复杂类型声明规则(1)-螺旋法则
“C/C++ 复杂类型声明规则” 将分为两节。第一节介绍螺旋法则声明规范,第二节介绍const的修饰关系。这两节内容,我都尝试以一种不用死记硬背,而是理解的方式去掌握。
本文参考自【初中生也能看懂的C/C++类型声明规则教学,很简单的!】 https://www.bilibili.com/video/BV1mB4y1L7HB/ 。里面通过一些例子介绍了螺旋法则。我将在此基础上加上我对其的解释,使其变得更加通俗易懂。
螺旋法则:
第一步,找到变量名,如果没有变置名,找到最里面的结构
第二步,向右看,读出你看到的东西但是不要跳过括号
第三步,再向左看,读出你看到的东西,但是也不要跳过括号
第四步,如果有括号的话,跳出一层括号
第五步,重复上述过程,直到你读出最终的类型
举例1:
1 | int *v[5]; |
- 第一步:
1 | int *v[5]; |
如上,我们找到了v
是变量名。读作:v
是……
- 第二步,向右看,读出你看到的东西但是不要跳过括号。
1 | int *v[5]; |
[5]
意为是一个5个元素的数组。读作:v是一个五个元素的数组。
- 第三步,再向左看,读出你看到的东西,但是也不要跳过括号。
1 | int *v[5]; |
int *
意为每个东西是一个指向int的指针。读作:v
是一个五个元素的数组,数组每个东西指向一个int型指针。
- 第四步,如果有括号的话,跳出一层括号。
1 | int *v[5]; |
对于上面这个例子,无这一步。我们已经读完了:v
是一个五个元素的数组,数组每个东西指向一个int型指针。
我们可以验证一下我们理解正不正确。我们可以用下列的代码给v数组赋值:
1 | int a = 2023; |
g++编译通过且运行正确,可见我们的理解没有问题。
举例2
1 | int (*func)() |
- 第一步:
1 | int (*func)() |
如上,我们找到了func
是变量名。读作:func
是……
- 第二步:向右看,读出你看到的东西但是不要跳过括号。
向右边遇到括号了,不跳出括号,skip。
- 第三步,再向左看,读出你看到的东西,但是也不要跳过括号。
1 | int (*func)() |
单独一个*意为“指向”。读作:func
指向……
- 第四步,如果有括号的话,跳出一层括号。向右看。
1 | int (*func)() |
这样一组括号是函数的意思。括号内为空,说明这个函数没有参数。整个(*func)
的左边是int
,它是这个函数的返回值,是int
。读作:func
指向一个接收空参且返回值为int
的函数。
我们可以验证一下我们理解正不正确。我们可以用下列的代码用匿名函数给func
赋值:
1 | int (*func1)(); |
g++编译通过且运行正确,可见我们的理解没有问题。
总结&一个网站推荐
螺旋法则五步骤;
当读的时候,看到[]
意为一个数组, ()
意为是一个函数,那么在主体的左侧肯定配套还会有一个返回值(当然,这个返回值也可能是一个复杂复合类型)。 *
如果单独出现,意为指向,如果和类型出现,如int*
,那就可以理解为指向int。
这里顺便推荐一个可以辅助阅读的网站:https://cdecl.org/ 。这个网站可以将表达式翻译成人话(英语),帮助大家的理解。但是总体来说只要会了螺旋法则,啥声明都能理解确切含义。
Numpy快速入门总览
本文是一个Python强大的计算库,NumPy(以下简称np)的入门介绍。在本文中,你会了解到:
- 什么是numpy?
- 为什么要用numpy?
- 从python内置list到numpy,有什么不同?
- 怎么安装与学习numpy?
因为网上numpy基础教程非常多,而且基本都覆盖了核心内容。因此,我不会再重复介绍numpy的一些基本操作,我只会留一些链接在第四部分。相反,我会从一些high-level的角度,介绍numpy,给读者构建一个大体印象。
1. 什么是numpy?
根据numpy官网( https://numpy.org/doc/stable/user/whatisnumpy.html )的介绍,numpy是一个python的科学计算库(如其名,numpy=numeric python)。他提供了多维数组等实用对象,和大量对数组的快速操作与算法。
NumPy is the fundamental package for scientific computing in Python. It is a Python library that provides a multidimensional array object, various derived objects (such as masked arrays and matrices), and an assortment of routines for fast operations on arrays.
2. 为什么要用numpy?
2.1 方便
python的内置list仅提供了一些简单操作,如append增加元素,sort排序元素等。如果要做一些复杂运算,就会略显吃力。numpy集成了大量的数学、数组操作函数,不需要自己造轮子了。例如直接使用np.corr()
就可以计算相关系数,直接使用np.linalg.inv()
就可以计算矩阵的逆矩阵,直接调用np.fft
模块可以进行一些傅立叶变换相关的操作。
2.2 快速高效
高效是numpy的核心亮点之一。我想可以分为程序运行高效和程序员编程高效。
运行高效:因为python是一种解释型语言,其运行速度比c/c++语言会慢几十倍左右。numpy的底层代码(见 https://github.com/numpy/numpy )都是使用c语言写的,并被高度优化过。因此其相同任务运行速度远快于python的list,和c++水平大抵相同。举个例子,两个2,000,000长的向量相加,纯用python list和for循环需要0.173s,而使用numpy则只需要0.008s。
编程高效:numpy里的许多运算符也被重载过,进行一般四则运算也很方便。如两个np.ndarray
a, b, 可以直接通过加号a+b
实现向量的逐位相加,而若是两个list a,b, a+b
只是将两个列表拼接起来。另外,numpy也实现了-
, *
, &
进行逐位相减、逐位向乘、逐位与的操作。下面是例子展示。
1 | # a, b are list |
2.3 Python数据科学之基础
许多python的科学计算、数据科学库都是以numpy为数据容器的基础根基的。例如sklearn(机器学习库)中的算法使用numpy来实现,用户传入的均为numpy.ndarray
数据;matplotlib(画图库)中接收numpy.ndarray
数组绘图,等等。因此numpy是要用python玩数据科学等领域的基础。学会numpy,可以做以下事情:
复现论文中的算法
研究一些数据科学库的源码,实现细节
掌握一个以python为接口的高性能计算的核心工具,做任何想做的事情
……
3. 从python list到numpy
从python的内置list列表到numpy的ndarray有一些“同”也有一些“不同”。这里简单进行一个介绍,以使读者可以对numpy数组有一个更清晰的大体影响。
numpy.ndarray
对象更像是其他编程语言(如C++/Java)里的数组(这样的数组结构才可以做到快速操作)。一旦构建,就要声明数组大小形状和数据类型。例如在C++中声明一个二维10*10的整型数组可以是:
1 | int array[10][10]; |
而与之对应,在numpy里声明这样一个数组是:
1 | array = np.ndarray(shape=(10, 10), dtype=int) |
而python中的list实现本质是一个动态数组,其长度会根据运行时来决定。
接下来,我便由此列几点numpy数组和list的不同:
- 改变大小。
因为list是动态数组,其长度会根据运行时来决定,因此list有append、pop等方法改变列表长短。而numpy.ndarray
数组则“一旦构建,就有固定的大小”。在运行时不能改变大小(有几个元素),只能改变形状(如每行每列有几个元素)。np.append()
方法虽说叫append,但是其本质也是要构建一个新的数组,而不是在原来的上做添加。
- 统一数据类型。
一个python list中可以存放不同类型,例如[1, 1.2f, 'str']
。
一个numpy数组具有统一的数据类型,这使得其indexing索引、存储效率远高于list。一个数组内只能是一个类型,例如np.int32
, int
, np.float32
, float
等。如果需要存储不同类型,则需要将类型设为object
。但是这样许多numpy函数便不支持使用了。
但是作为python语言的模块,numpy的设计还是非常清晰易懂的。大体上就是创建数组对象,然后对其进行运算或函数操作。语法上也非常相近。例如,numpy也支持list的切片索引(如a[::2]
,且其功能玩法更多)。
4. 怎么安装与学习numpy?
4.1 安装
网上的教程非常多,涵盖Windows,macOS和Linux系统。只需在网上找到相关教程即可。使用anaconda、miniconda、pip安装都可以。
4.2 学习
以个人经验来看,numpy的学习胜在多用。只要用得多,自然而然就熟练、学会了。numpy已经包含了大部分需要用的函数,如有对应需求,一定要先去网上搜索看看有无相关函数(现在还有chatGPT之类的可以问了)。
对于新手朋友我在这里推荐几个学习资源链接:
NumPy官网 官方文档 https://numpy.org/doc/stable/index.html
【一个10分钟的numpy入门教程】(十分推荐) https://www.bilibili.com/video/BV1Wy4y1h7ii/?share_source=copy_web&vd_source=0c067fd928325f3684e2a932b9539e44
NumPy 教程 菜鸟教程(文字+例子,较全面): https://www.runoob.com/numpy/numpy-tutorial.html
全网最全Numpy图解教程 知乎(有很多图,生动形象)https://zhuanlan.zhihu.com/p/528144539
百度 Google搜索 (以“numpy xxxxxx”提问,基本上都会有想要的回答的)
我在其他平台发的文章链接
这里会摆放我在其他平台上写的文章的链接(因为我懒得搬过来了),欢迎点击阅读。
原生word仿制latex伪代码块,数学建模、作业报告均适用!【带图手把手教学】 https://zhuanlan.zhihu.com/p/472381746
个人炼丹炉配置经验分享(上):利用校园网LAN启动、智能插座远程启动并远程桌面连接 https://zhuanlan.zhihu.com/p/460263000
个人炼丹炉配置经验分享(下):利用JupyterLab实现何时何地都可远程炼丹 https://zhuanlan.zhihu.com/p/461491632
【新手向】Python x VS Code 简单debug与调试 https://zhuanlan.zhihu.com/p/357874811
【新手向】Python x VS Code debug按钮 与 进阶debug介绍 https://zhuanlan.zhihu.com/p/359283509
Matplotlib Quick Reference
Cheatsheet
来自mpl官网的 https://matplotlib.org/cheatsheets/cheatsheets.pdf 的官方cheatsheet,但是pdf不方便即时查看,遂导出成图片,可以存到相册。图片可以单击后放大查看。
page1:
page2:
这里面覆盖了大部分使用mpl时会用到的函数,详细使用方法可见官网(https://matplotlib.org/)。
本文后续将会挑一些进行额外解释。
colormap class
colormap是把图变好看的灵魂。属于matplotlib.colors.Colormap()
类. 这个类实现了__call__()
方法,因此可以传入一个介于0-1之间的数,其返回一个四元组,表示一个RGBA颜色。这个元组可以被mpl的各类画图函数接收。
基础用法:
1 | import matplotlib.pyplot as plt |
实践用法:画一条渐变的线。官网有例子 https://matplotlib.org/stable/gallery/lines_bars_and_markers/multicolored_line.html#sphx-glr-gallery-lines-bars-and-markers-multicolored-line-py, 我这是另一种实现方法。
1 | import matplotlib.pyplot as plt |
效果:
Hello World (Hexo Quick Reference)
This blog is built with Hexo! This is the originally first post, automatically generated by Hexo. I modified it to a Quick Reference Handbook (QRH) for using this.
Quick Start
Create a new post
1 | $ hexo new "My New Post" |
More info: Writing
Clean cache
1 | $ hexo clean |
Generate static files
1 | $ hexo generate |
More info: Generating
Run server (local testing)
1 | $ hexo server |
More info: Server
Deploy to remote sites
1 | $ hexo deploy |
More info: Deployment