前言
本文主要是针对陈云的PyTorch入门与实践的第八章的内容进行复现,准确地说,是看着他写的代码,自己再实现一遍,所以更多地是在讲解实现过程中遇到的问题或者看到的好的方法,而不是针对论文的原理的进行讲解。对于原理,也只是会一笔带过。原理篇暂时不准备留坑,因为原理是个玄学。
这是我的代码
大神链接:https://github.com/anishathalye/neural-style
这是论文作者写的
问题及其思考
data是鸭子类型
因为data作为tensor,已经实现了__getitem__和__len__方法,可以被DataLoader加载。
或者说,只要能类似鸭子就可以,这方面掌握得还不熟悉。
LSTM的输入
作者明确提出,LSTM的输入类型是(seq_len, batch_size, embedding_dim),除去embedding_dim,就是(seq_len, batch_size),原因很简单,LSTM是每次输入一个字,输出一个字,那么输入就是x[0],对于图像,x[0]就是一张图片,那么对于文字,x[0]也应该就是一个字。好吧,还是说不通,等以后看了相关资料说不定才能理解。
代码编写
1 | # 变成列表,方便后续的操作,因为start_words的每个字用过之后就没用了, |
os.walk() && os.listdir()
os.walk()
1 | In [6]: for i,j,k in os.walk('./'): |
os.walk()返回的是当前文件夹下所有的可遍历的文件夹,生成的生成器,i表示文件夹,j表示i文件夹下的文件夹,k表示i文件夹下的文件。以上是os.walk的for用法,下面是直接的用法。对于文件访问,直接i+k,对于文件夹访问,i+j即可。
os.listdir()
1 | In [17]: aa = os.walk('./') |
不知道为什么这里不能直接用 aa,bb,cc = os.walk(‘./‘)1
2
3
4
5
6
7
8
9
10In [22]: for ii in os.listdir('./'):
...: print(ii)
...:
1
b
a
In [23]: aa = os.listdir('./')
In [24]: aa
Out[24]: ['1', 'b', 'a']
os.listdir()返回的是当前文件夹下的文件夹或者文件。
现在碰到的情况是文件夹排列有序,直接访问文件,所以os.list()就可以了。
对应的就是1
2for filename in os.listdir(src):
path = os.path.join(src,filename)
小发现
- 刚刚发现github上的chinese中的某个文件夹是一个新的github文件。这是个啥情况
- python 可以在函数内部定义函数,是局部域,不能被外界访问,很好,这样就相当于说明了哪些函数是为哪些函数服务的。
json数据格式的读取
1 | In [25]: import json |
json文件的读取
第一种:此时data里是该文件内的全部数据1
2with open(file,'r') as f:
data = json.load(f)
第二种:此时data也是该文件内的全部数据,open(file).read()表示读取数据1
data = json.loads(open(file).read())
显然第一种安全,第二种还需要显示地关闭文件
可以使用pprint来打印data,好看1
2import pprint import pprint
pprint data
正则表达式
普通字符和11个元字符:
. 匹配任意除换行符”\n”外的字符(在DOTALL模式中也能匹配换行符 a.c
\ 转义字符,使后一个字符改变原来的意思
* 匹配前一个字符0或多次
+ 匹配前一个字符1次或无限次
? 匹配一个字符0次或1次
^ 匹配字符串开头。在多行模式中匹配每一行的开头
$ 匹配字符串末尾,在多行模式中匹配每一行的末尾
| 或。匹配|左右表达式任意一个,从左到右匹配,如果|没有包括在()中,则它的范围是整个正则表达式
{} {m}匹配前一个字符m次,{m,n}匹配前一个字符m至n次,若省略n,则匹配m至无限次
[] 字符集。对应的位置可以是字符集中任意字符。字符集中的字符可以逐个列出,也可以给出范围,如[abc]或[a-c]。abc表示取反,即非abc。
所有特殊字符在字符集中都失去其原有的特殊含义。用\反斜杠转义恢复特殊字符的特殊含义。
()表达式作为一个整体,可以后接数量词。表达式中的|仅在该组中有效。
print re.split(r”;|,|\?”, line1)
print re.split(r”[;,?]”, line1)
print re.split(r”\W+”, line)
不知道为什么1
2
3
4
5para = '-181-欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]'
re.subn('[\d-]','',para)
('欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]', 5)
re.subn('[\d-]*','',para)
('欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]', 38)
list越界与切片
list不能越界索引访问,但是对于切片,切片是会自动匹配长度的,所以使用slice不需要担心越界问题。1
2
3
4
5
6s = [1,2,3]
s[8] # 报错
s[1] == 1
s[:1] == [1]
s[1:10] # return s[1:3]
索引位置返回的是元素的副本
切片返回的是list的副本
嵌套列表压平
func = lambda x: [y for l in x for y in l] if type(x) is list else [x]
tuple的连接
1 | (1,2)+(3,4) == (1,2,3,4) |
求list的size
1 | li = [[1,2],[3,4]] |
异常触发
参考链接http://www.runoob.com/python/python-exceptions.html
等总结的时候尝试一下
分为捕捉异常和触发异常
捕捉异常
1 | # 捕捉异常第一种 try/except语句 |
触发异常
1 | # 函数触发异常 |
自定义异常
1 | >>>class MyError(Exception): |
list的更新
更新分为逐元素更新和逐列表更新
逐元素更新
1 | # list的逐元素更新 |
即对于一个空列表的append,我们总是可以将其转化成列表推导式,
并且对于dict和set,只需要将中括号换成大括号即可
逐列表更新
1 | # list的逐列表更新 |
注:append()和extend()和+=都是在原有列表增加,+是生成一个新的列表
感觉逐列表更新应该可以更优美.
os.path.join()
1 | In [42]: import os |
对os.path.join()总结如下:从后往前,遇到绝对路径,则绝对路径前面的元素丢弃,遇到类似’…/‘,则将其看成一个普通的路径名字,而对于/在末尾的,会自动根据情况补充。
list()和[]的区别,字符串分割成单个字符
1 | In [58]: list('abcd') |
即,list()会拆解输入值,拼接成list,可以用在’abcd’这样的字符串直接拆成’a’,’b’,’c’,’d’这样的形式,因为re.split不支持这种拆分法。当然,如果只是单纯地逐元素访问并逐元素地进行操作,我们可以使用for i in ‘abcd’:这样的访问。
也可以认为是’’.join()的逆操作1
2
3
4
5
6
7In [65]: bb = ['abc']
In [66]: list(*bb)
Out[66]: ['a', 'b', 'c']
In [71]: ''.join(list(bb))
Out[71]: 'abc'
list、dict和numpy的互相转换
1 | In [74]: c = np.array({'a':1,'b':2}) |
shell的基础教程
1 | for fff in `ls *.json` |
shell 传递参数
1 | !/bin/bash |
shell 流程控制
1 | if condition1 |
Shell 输入/输出重定向
命令 说明
command > file 将输出重定向到 file。
command < file 将输入重定向到 file。
command >> file 将输出以追加的方式重定向到 file。
n > file 将文件描述符为 n 的文件重定向到 file。
n >> file 将文件描述符为 n 的文件以追加的方式重定向到 file。
n >& m 将输出文件 m 和 n 合并。
n <& m 将输入文件 m 和 n 合并。
<< tag 将开始标记 tag 和结束标记 tag 之间的内容作为输入。
需要注意的是文件描述符 0 通常是标准输入(STDIN),1 是标准输出(STDOUT),2 是标准错误输出(STDERR)。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22如果希望 stderr 重定向到 file,可以这样写:
command 2 > file
如果希望将 stdout 和 stderr 合并后重定向到 file
command > file 2>&1
command >> file 2>&1
如果希望对 stdin 和 stdout 都重定向
command < file1 >file2
Here Document 是 Shell 中的一种特殊的重定向方式,用来将输入重定向到一个交互式 Shell 脚本或程序。
wc -l << EOF
欢迎来到
菜鸟教程
www.runoob.com
EOF
3 # 输出结果为 3 行
如果希望执行某个命令,但又不希望在屏幕上显示输出结果,那么可以将输出重定向到 /dev/null:
command > /dev/null
如果希望屏蔽 stdout 和 stderr,可以这样写:
command > /dev/null 2>&1
str.split(‘’)
以列表形式返回1
2
3
4label_dim = '16803+100'
cc = label_dim.split('+')
cc
['16803','100']
map
1 | scales_tr = '20,20--20,20' |
tensor的拼接 t.cat t.stack
1 | result = [] |
tensor.view()
1 | x = x.view(x.size(0),-1) |
Inception-V3
参考链接https://www.jianshu.com/p/3bbf0675cfce
https://blog.csdn.net/loveliuzz/article/details/79135583
其中都有一些错误,还需要看着源码纠正一下。
python 文件IO
python中的三个读read(),readline()和readlines()
.read() 每次读取整个文件,它通常用于将文件内容放到一个字符串变量中,然而 .read() 生成文件内容最直接的字符串表示,但对于连续的面向行的处理,它却是不必要的
.readlines()之间的差异是后者一次读取整个文件,象 .read()一样。.readlines()自动将文件内容分析成一个行的列表,该列表可以由 Python 的 for… in … 结构进行处理
.readline()每次只读取一行
python打开多个文件
1 | with open('a.txt', 'r') as a, open('b.txt', 'r') as b: |
1 | #!/usr/bin/env python |
python csv
在使用常规的读取文件的方法的时候,出现了问题,每一个数字包括小数点都被当成了一个字符,这样明显是不对的,对于数字的csv,要考虑下这个方法,我感觉应该和写的方式有关,待续。
参考链接https://www.cnblogs.com/dmir/p/5009075.html1
2
3
4
5with open(path) as f:
f_csv = csv.reader(f)
headers = next(f_csv)
for i in f_csv:1
2import pandas as pd
csv_data = pd.read_csv(path)
优化器
优化器与模型参数完全共享内存,一个改变,另一个会立即跟着改变。
不能重复加载同一个参数1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139# 第一种
optimizer = t.optim.Adam(model.parameters(), lr = 0.1)
optimizer
Adam (
Parameter Group 0
amsgrad: False
betas: (0.9, 0.999)
eps: 1e-08
lr: 0.1
weight_decay: 0
)
for i in optimizer.param_groups:
print(i)
print('______')
{'params': [Parameter containing:
tensor([[[[ 0.0493, 0.1696, 0.0647],
[ 0.1935, 0.3102, -0.0871],
[-0.2787, 0.0894, -0.0438]]],
[[[-0.2671, 0.2079, 0.2474],
[ 0.2068, -0.1825, 0.1427],
[-0.0853, -0.1799, -0.2465]]]]), Parameter containing:
tensor([-0.3158, 0.1429]), Parameter containing:
tensor([[[[ 0.2063, 0.0771, 0.1579],
[ 0.1543, 0.1374, -0.1951],
[-0.1221, 0.0099, -0.1331]],
[[-0.1899, 0.1978, 0.1065],
[ 0.1400, -0.0740, 0.0397],
[-0.2165, -0.0180, 0.1072]]],
[[[ 0.0692, -0.1296, 0.0524],
[ 0.0577, -0.1184, 0.0697],
[ 0.0859, -0.2086, 0.0419]],
[[-0.0270, 0.1836, -0.0649],
[ 0.1680, -0.1061, -0.2357],
[-0.0408, 0.0799, 0.0065]]]]), Parameter containing:
tensor([ 0.1269, -0.1582]), Parameter containing:
tensor([[[[ 0.0185, -0.2579, -0.1185],
[ 0.1269, 0.0274, 0.1019],
[ 0.0329, -0.1229, -0.1922]]]]), Parameter containing:
tensor([-0.2731])], 'lr': 0.1, 'betas': (0.9, 0.999), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False}
______
# 第二种
optimizer = t.optim.Adam([{'params':model.net1.parameters(),'lr':0.4},
{'params':model.net2.parameters(),'lr':0.1}],lr=0.04)
optimizer
Adam (
Parameter Group 0
amsgrad: False
betas: (0.9, 0.999)
eps: 1e-08
lr: 0.4
weight_decay: 0
Parameter Group 1
amsgrad: False
betas: (0.9, 0.999)
eps: 1e-08
lr: 0.1
weight_decay: 0
)
for i in optimizer.param_groups:
print(i)
print('______')
{'params': [Parameter containing:
tensor([[[[ 0.0493, 0.1696, 0.0647],
[ 0.1935, 0.3102, -0.0871],
[-0.2787, 0.0894, -0.0438]]],
[[[-0.2671, 0.2079, 0.2474],
[ 0.2068, -0.1825, 0.1427],
[-0.0853, -0.1799, -0.2465]]]]), Parameter containing:
tensor([-0.3158, 0.1429])], 'lr': 0.4, 'betas': (0.9, 0.999), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False}
______
{'params': [Parameter containing:
tensor([[[[ 0.2063, 0.0771, 0.1579],
[ 0.1543, 0.1374, -0.1951],
[-0.1221, 0.0099, -0.1331]],
[[-0.1899, 0.1978, 0.1065],
[ 0.1400, -0.0740, 0.0397],
[-0.2165, -0.0180, 0.1072]]],
[[[ 0.0692, -0.1296, 0.0524],
[ 0.0577, -0.1184, 0.0697],
[ 0.0859, -0.2086, 0.0419]],
[[-0.0270, 0.1836, -0.0649],
[ 0.1680, -0.1061, -0.2357],
[-0.0408, 0.0799, 0.0065]]]]), Parameter containing:
tensor([ 0.1269, -0.1582]), Parameter containing:
tensor([[[[ 0.0185, -0.2579, -0.1185],
[ 0.1269, 0.0274, 0.1019],
[ 0.0329, -0.1229, -0.1922]]]]), Parameter containing:
tensor([-0.2731])], 'lr': 0.1, 'betas': (0.9, 0.999), 'eps': 1e-08, 'weight_decay': 0, 'amsgrad': False}
______
optimizer.state_dict()
{'state': {},
'param_groups': [{'lr': 0.4,
'betas': (0.9, 0.999),
'eps': 1e-08,
'weight_decay': 0,
'amsgrad': False,
'params': [140617843939944, 140617843755120]},
{'lr': 0.1,
'betas': (0.9, 0.999),
'eps': 1e-08,
'weight_decay': 0,
'amsgrad': False,
'params': [140617843755192,
140617843755264,
140617843755336,
140617843755408]}]}
# 第三种
optimizer = t.optim.Adam([{'params':model.net1.parameters(),'lr':0.4}])
optimizer.add_param_group({'params':model.net2.parameters(),'lr':0.3})
# 第四种
for param_group in optimizer.param_groups:
param_group['lr']=lr_new
模型保存
1 | # 只保留模型参数并且加载 |
numpy和list和tensor对于size的访问区别
- list: 只有len()方法,返回的是最外层的个数,reshape方法
- numpy: b.size是全部个数,b.shape是(2,3) b = np.arange(6).reshape(2,3), b.resize(2,3) np.arange(1,6,2)
- tensor: c.shape==c.size() len(c)==c.size(0) 返回torch.size([3,2]), c.resize_(4,4)(可以改变自身尺寸) c.resize(1,4)(来源于torchvision,可以忽略)==c.reshape(1,4)(对于连续地址共享内存,不连续地址则复制)==c.view(1,4)(共享内存) t.arange(1,6,2) t_.unsqueeze(1)
tensor的普通索引基本共享内存,而高级索引基本不共享内存。 - numpy—>tensor t = t.from_numpy(numpy)(共享内存)或者 t = t.tensor(numpy)(返回新对象)
- tensor—>numpy np = t.numpy()(共享内存) 或者 np = np.array(t)
- numpy—>list list = np.tolist()(不共享内存)
- list—>numpy np = np.array(list)(不共享内存)
- tensor—>list list = t.tolist() (不共享内存) 或者 item = t.item() (不共享内存)
- list—>tensor t = t.tensor(list)(不共享内存)
也就是说numpy和tensor可以做到互相共享内存,而list只是一个对外的和Python相连接的一个形式.
补充:基于numpy和tensor,推荐使用shape属性, 修改形状则分别使用reshape()和view(),
1 | import numpy as np |
torch.Tensor 和 torch.tensor的区别
暂时还没有组织好的语言,先以代码的形式记录下来
主要是类型和对0维元素的区别。1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26In [12]: import torch as t
In [13]: t.Tensor(3)
Out[13]: tensor([-4.8232e+13, 4.5581e-41, -1.8931e-03])
In [14]: t.Tensor([3,4])
Out[14]: tensor([ 3., 4.])
In [15]: t.tensor(3)
Out[15]: tensor(3)
In [16]: t.tensor([3,4])
Out[16]: tensor([ 3, 4])
In [17]: a = t.tensor([3,4])
In [18]: type(a)
Out[18]: torch.Tensor
In [19]: a.dtype
Out[19]: torch.int64
# Tensor只是tensor(dtype=float)的别名。
x = torch.tensor([3.0],requires_grad=True)
# torch.Tensor不接收requires_grad参数
# torch.tensor只有是float型参数的情况下才接受requires_grad参数
tensor.new()和tensor.data.new()
暂时不知道这两者的区别,但是书上的代码多数都是tensor.data.new()
topk的用法
output.data[0].topk(1)[1][0].item()1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19In [20]: x = t.arange(1,6)
In [21]: y = t.topk(x,2)
In [22]: type(y)
Out[22]: tuple
In [23]: y
Out[23]: (tensor([ 5., 4.]), tensor([ 4, 3]))
In [24]: y[1]
Out[24]: tensor([ 4, 3])
In [25]: y[1][1]
Out[25]: tensor(3)
In [26]: y[1][1].item()
Out[26]: 3
ipython和jupyter和pycharm
在写代码的前期,用jupyter好使,因为对于不确定的比较多的代码是可以直接看到结果,对某一段进行调试,检查某一段的基本语法错误,或者对于某个想法的实现,是简单直接的甚至对于中型代码,用代码框可以实现视觉上的分离,逻辑清晰,并且支持markdown的记录与注释,对于不了解的代码有很好的支持性。
但是在写代码的后期,jupyter的弊端逐渐显现,不能使用模板,init.py的生成不好使,文件与文件夹的关系不清晰。甚至一个简单的文件或者文件夹挪动位置都很麻烦,需要桌面的辅助。
而pycharm对于文件管理,init.py等有很好的支持性。更适合写已经成熟的代码。
这一下难住我了,作为新手,肯定每次都要实验好些代码,看输入输出的效果,如果是pycharm则比较麻烦,对于调试很啰嗦。
命令行窗口做为补充,也不好使,因为每次能看到的东西有限,重复性差,只能用于单句代码的验证。
所以不妨这样,前期开发还是用jupyter,等开发的差不多了,甚至等单个文件已经开发完毕,这样的话开发就可以先不管文件夹的事,等各个文件开发完毕,再转成pycharm,来实现文件夹、文件的组织管理和后期的调试,这是因为现在多数不使用jupyter直接运行,而是使用py进行运行。我觉得应该有很多人用.ipynb进行运行,但是我不知道怎么才能更好的运行。
anaconda
虚拟环境不错
python
如果在 Python 脚本文件首行输入#!/usr/bin/env python,那么可以在命令行窗口中执行/path/to/script-file.py以执行该脚本文件。
使用三引号(‘’’或”””)可以指定一个多行字符串。