0%

pytorch chapter9 CharRNN

前言

本文主要是针对陈云的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
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
# 变成列表,方便后续的操作,因为start_words的每个字用过之后就没用了,
# 用pop不行,因为对于空列表会报错,用None作为结尾标志。可以看出,如果我们想让某个序列正常退出,可以通过设置特殊的结尾来实现。
# 这一段的逻辑有点乱,因为prefix_words可能没有,所以对于start_words,必须先进行一个模型生成。
# 对于或有或无的perfix_words,为了消除其存在对代码和思路的影响,应该保证prefix_words前后的代码状态不变,即
"""
第一种
这种保证了output,hidden的状态不变
output, hidden = model(input, hidden)

# step: 对prefix_words进行输入
prefix_words = '' if prefix_words==None else prefix_words
for word in prefix_words:
input = input.data.new(word2ix[word]).view(1,1)
output, hidden = model(input, hidden)

for i in range(opt.max_gen_len-1):
top_index = output[0].topk(1)[1][0].item()
...
output, hidden = model(input, hidden)

第二种
这种保证了input的状态不变
for word in prefix_words:
output, hidden = model(input, hidden)
input = (input.data.new([word2ix[word]])).view(1, 1)

for i in range(opt.max_gen_len):
output, hidden = model(input, hidden)
top_index = output.data[0].topk(1)[1][0].item()


决定采用第二种,因为代码的主体思路是for i in range(opt.max_gen_len),prefix_word是插入部分,是可有可无部分。
第一种会造成 top_index与model的切分,不利于后期分析。
或者说,以后碰到这种类型的代码,可以直接跳过中间部分,对后面进行分析。


os.walk() && os.listdir()

os.walk()

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
In [6]: for i,j,k in os.walk('./'):
...: print(i)
./
./b
./a
./a/aa2
./a/aa1

In [7]: for i,j,k in os.walk('./'):
...: print(j)
['b', 'a']
[]
['aa2', 'aa1']
[]
[]

In [8]: for i,j,k in os.walk('./'):
...: print(k)
['1']
['cc', 'bb']
['aa']
['bbb']
[]

i+k即可

os.walk()返回的是当前文件夹下所有的可遍历的文件夹,生成的生成器,i表示文件夹,j表示i文件夹下的文件夹,k表示i文件夹下的文件。以上是os.walk的for用法,下面是直接的用法。对于文件访问,直接i+k,对于文件夹访问,i+j即可。

os.listdir()

1
2
3
4
5
6
7
8
9
10
11
In [17]: aa = os.walk('./')

In [18]: bb = list(aa)

In [19]: bb
Out[19]:
[('./', ['b', 'a'], ['1']),
('./b', [], ['cc', 'bb']),
('./a', ['aa2', 'aa1'], ['aa']),
('./a/aa2', [], ['bbb']),
('./a/aa1', [], [])]

不知道为什么这里不能直接用 aa,bb,cc = os.walk(‘./‘)

1
2
3
4
5
6
7
8
9
10
In [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
2
for filename in os.listdir(src):
path = os.path.join(src,filename)


小发现

  • 刚刚发现github上的chinese中的某个文件夹是一个新的github文件。这是个啥情况
  • python 可以在函数内部定义函数,是局部域,不能被外界访问,很好,这样就相当于说明了哪些函数是为哪些函数服务的。

json数据格式的读取

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
In [25]: import json

In [26]: s = {"name": "ACME", "shares": 50, "price": 490.1}

In [27]: json_str = json.dumps(s)

In [28]: json_str.__class__
Out[28]: str

In [29]: json_str
Out[29]: '{"name": "ACME", "shares": 50, "price": 490.1}'

In [33]: ss = json.loads(json_str)

In [34]: ss
Out[34]: {'name': 'ACME', 'shares': 50, 'price': 490.1}

json文件的读取

第一种:此时data里是该文件内的全部数据

1
2
with open(file,'r') as f:
data = json.load(f)

第二种:此时data也是该文件内的全部数据,open(file).read()表示读取数据
1
data = json.loads(open(file).read())

显然第一种安全,第二种还需要显示地关闭文件
可以使用pprint来打印data,好看
1
2
import 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
5
para = '-181-欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]'
re.subn('[\d-]','',para)
('欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]', 5)
re.subn('[\d-]*','',para)
('欲出未出光辣达,[千山]万山[如火]发(哈哈哈大笑)。须臾[走向][天上]', 38)


list越界与切片

list不能越界索引访问,但是对于切片,切片是会自动匹配长度的,所以使用slice不需要担心越界问题。

1
2
3
4
5
6
s = [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
2
3
(1,2)+(3,4) == (1,2,3,4)
# 定义只有一个数字的tuple,避免函数歧义
t = (1,)

求list的size

1
2
3
li = [[1,2],[3,4]]
tu = np.asarray(li).shape
# shape返回的是tuple型,可以直接拼接

异常触发

参考链接http://www.runoob.com/python/python-exceptions.html
等总结的时候尝试一下
分为捕捉异常和触发异常

捕捉异常

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
# 捕捉异常第一种 try/except语句
try:
<语句> #运行别的代码
except <名字>:
<语句> #如果在try部份引发了'name'异常
except <名字>,<数据>:
<语句> #如果引发了'name'异常,获得附加的数据
else:
<语句> #如果没有异常发生

# 捕捉异常第二种 try/finally
try:
<语句>
finally:
<语句> #退出try时总会执行
raise

# 实例1
import sys

try:
f = open('myfile.txt')
s = f.readline()
i = int(s.strip())
except OSError as err:
print("OS error: {0}".format(err))
except ValueError:
print("Could not convert data to an integer.")
except:
print("Unexpected error:", sys.exc_info()[0])
raise

# 实例2
如果你只想知道这是否抛出了一个异常,并不想去处理它,那么一个简单的 raise 语句就可以再次把它抛出。
try:
raise NameError('HiThere')
except NameError:
print('An exception flew by!')
raise

# 实例3
处理有参数的异常
def temp_convert(var):
try:
return int(var)
except (ValueError) as Argument:
print ("参数没有包含数字\n", Argument)

# 调用函数
temp_convert("xyz");

# 捕捉异常共同使用
try:
fh = open("testfile", "w")
try:
fh.write("这是一个测试文件,用于测试异常!!")
finally:
print "关闭文件"
fh.close()
except IOError:
print "Error: 没有找到文件或读取文件失败"

# 注
except (RuntimeError, TypeError, NameError):

触发异常

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
# 函数触发异常
def functionName( level ):
if level < 1:
raise Exception("Invalid level!", level)
# 触发异常后,后面的代码就不会再执行

# 捕捉异常和触发异常的配合
def mye( level ):
if level < 1:
raise Exception("Invalid level!")
# 触发异常后,后面的代码就不会再执行
try:
mye(0) # 触发异常
except Exception:
print 1
else:
print 2

自定义异常

1
2
3
4
5
6
7
8
9
10
11
>>>class MyError(Exception):
def __init__(self, value):
self.value = value
def __str__(self):
return repr(self.value)

>>> try:
raise MyError(2*2)
except MyError as e:
print('My exception occurred, value:', e.value)


list的更新

更新分为逐元素更新和逐列表更新

逐元素更新

1
2
3
4
5
6
7
8
9
10
11
12
13
14
# list的逐元素更新
li = []
for i in range(5):
li.append(i)
# 对于空列表,等价于
li = [i for i in range(5)]
# 或者等价于generator
li = (i for i in range(5))
# 或者转化为逐列表更新,常用与列表头和列表尾同时更新
for i in range(4):
li=[i]+li+[i+11]
# 或者对于已经得到的元素
[a,b,c]

即对于一个空列表的append,我们总是可以将其转化成列表推导式,
并且对于dict和set,只需要将中括号换成大括号即可

逐列表更新

1
2
3
4
5
6
7
8
9
# list的逐列表更新
li = []
ll = [[1,2,3],[4,5,6]]
for i in ll:
li.extend(i)
li
[1,2,3,4,5,6]
# 或者对于有限个列表
c = a+b

注:append()和extend()和+=都是在原有列表增加,+是生成一个新的列表
感觉逐列表更新应该可以更优美.

os.path.join()

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
In [42]: import os

In [43]: print("1:",os.path.join('aaaa','bbbb','ccccc.txt'))
1: aaaa/bbbb/ccccc.txt

In [44]: print("1:",os.path.join('/aaaa','bbbb','ccccc.txt'))
1: /aaaa/bbbb/ccccc.txt

In [45]: print("1:",os.path.join('aaaa','/bbbb','ccccc.txt'))
1: /bbbb/ccccc.txt

In [46]: print("1:",os.path.join('aaaa','bbbb','/ccccc.txt'))
1: /ccccc.txt

In [47]: print("1:",os.path.join('aaaa','/bbbb','/ccccc.txt'))
1: /ccccc.txt

In [48]: print("1:",os.path.join('aaaa','./bbbb','ccccc.txt'))
1: aaaa/./bbbb/ccccc.txt

In [49]: print("1:",os.path.join('aaaa','../bbbb','ccccc.txt'))
1: aaaa/../bbbb/ccccc.txt

In [50]: print("1:",os.path.join('aaaa','bbbb','./ccccc.txt'))
1: aaaa/bbbb/./ccccc.txt

In [51]: print("1:",os.path.join('aaaa','bbbb','../ccccc.txt'))
1: aaaa/bbbb/../ccccc.txt

In [54]: print("1:",os.path.join('aaaa','/bbbb','....../ccccc.txt'))
1: /bbbb/....../ccccc.txt

In [55]: print("1:",os.path.join('aaaa','bbbb/','ccccc.txt'))
1: aaaa/bbbb/ccccc.txt

In [57]: print("1:",os.path.join('aaaa','bbbb\\','ccccc.txt'))
1: aaaa/bbbb\/ccccc.txt

对os.path.join()总结如下:从后往前,遇到绝对路径,则绝对路径前面的元素丢弃,遇到类似’…/‘,则将其看成一个普通的路径名字,而对于/在末尾的,会自动根据情况补充。

list()和[]的区别,字符串分割成单个字符

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
In [58]: list('abcd')
Out[58]: ['a', 'b', 'c', 'd']

In [59]: ['abcd']
Out[59]: ['abcd']

In [61]: aa = (1,2)

In [62]: list(aa)
Out[62]: [1, 2]

In [63]: [aa]
Out[63]: [(1, 2)]

In [65]: bb = ['abc']

In [66]: list(*bb)
Out[66]: ['a', 'b', 'c']

for i in 'abcd':
print(i)

即,list()会拆解输入值,拼接成list,可以用在’abcd’这样的字符串直接拆成’a’,’b’,’c’,’d’这样的形式,因为re.split不支持这种拆分法。当然,如果只是单纯地逐元素访问并逐元素地进行操作,我们可以使用for i in ‘abcd’:这样的访问。
也可以认为是’’.join()的逆操作

1
2
3
4
5
6
7
In [65]: bb = ['abc']

In [66]: list(*bb)
Out[66]: ['a', 'b', 'c']

In [71]: ''.join(list(bb))
Out[71]: 'abc'


list、dict和numpy的互相转换

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
In [74]: c = np.array({'a':1,'b':2})
In [75]: c[0]
---------------------------------------------------------------------------
IndexError Traceback (most recent call last)
<ipython-input-75-71463270cd6c> in <module>()
----> 1 c[0]

IndexError: too many indices for array

In [77]: c
Out[77]: array({'a': 1, 'b': 2}, dtype=object)
In [79]: c.tolist()
Out[79]: {'a': 1, 'b': 2}

In [80]: d = c.tolist()

In [81]: d.__class__
Out[81]: dict

shell的基础教程

1
2
3
4
5
6
7
8
for fff in `ls *.json`
do
cconv -f utf8-tw -t UTF8-CN $fff -o simplified/$fff
done

for skill in Ada Coffe Action Java; do
echo "I am good at ${skill}Script"
done

shell 传递参数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
# author:菜鸟教程
# url:www.runoob.com

echo "Shell 传递参数实例!";
echo "执行的文件名:$0";
echo "第一个参数为:$1";
echo "第二个参数为:$2";
echo "第三个参数为:$3";

$ chmod +x test.sh
$ ./test.sh 1 2 3
Shell 传递参数实例!
执行的文件名:./test.sh
第一个参数为:1
第二个参数为:2
第三个参数为:3

shell 流程控制

1
2
3
4
5
6
7
8
9
if condition1
then
command1
elif condition2
then
command2
else
commandN
fi

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
4
label_dim = '16803+100'
cc = label_dim.split('+')
cc
['16803','100']

map

1
2
3
4
5
6
scales_tr = '20,20--20,20'
scale = [map(int, x.split(',')) for x in scales_tr.split('--')]
scale
[<map at 0x7fd798714748>, <map at 0x7fd798714588>]
list(scale[0])
[20,20]

tensor的拼接 t.cat t.stack

1
2
3
4
5
result = []
for ii in index:
# tensor的截取与合并 cat, stack,cat+view=stack,stack 新增维度进行合并
result.append(fake_img.data[ii])
tv.utils.save_image(t.stack(result), opt.gen_img, normalize=True, range=(-1,1))

tensor.view()

1
2
3
x = x.view(x.size(0),-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
2
3
with open('a.txt', 'r') as a, open('b.txt', 'r') as b:
print(a.read())
print(b.read())
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
#!/usr/bin/env python
# coding: utf-8


class open_many:

def __init__(self, files=None, mode='r'):
if files is None:
self._files = []
else:
self._files = files
self.mode = mode
self.fds = [] # fd is short for file descriptor

def __enter__(self):
print('-->enter')
for f in self._files:
print('-->opening file')
self.fds.append(open(f, self.mode))
return self.fds

def __exit__(self, exc_type, exc_val, traceback):
print('-->exit')
for fd in self.fds:
print('-->closing file')
fd.close()
if exc_type == ValueError:
print('-->exception: ' + str(exc_val))
return True


if __name__ == '__main__':
print('')
with open_many(['a.txt', 'b.txt'], 'r') as files:
for f in files:
print f.read()
print('')
with open_many() as files:
raise ValueError('captured')
print('')
with open_many() as files:
raise Exception('uncaptureable')

python csv

在使用常规的读取文件的方法的时候,出现了问题,每一个数字包括小数点都被当成了一个字符,这样明显是不对的,对于数字的csv,要考虑下这个方法,我感觉应该和写的方式有关,待续。
参考链接https://www.cnblogs.com/dmir/p/5009075.html

1
2
3
4
5
with open(path) as f:
f_csv = csv.reader(f)
headers = next(f_csv)
for i in f_csv:


1
2
import 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
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
# 只保留模型参数并且加载
t.save(model.state_dict(),'model_state_dict')
model.state_dict()

OrderedDict([('net1.weight', tensor([[[[-0.3164, -0.2508, -0.3294],
[ 0.2388, -0.1582, 0.0678],
[ 0.0194, 0.1120, 0.2794]]],


[[[-0.2425, 0.0833, -0.0842],
[ 0.0687, -0.0637, -0.3034],
[-0.3268, -0.1049, -0.0286]]]])),
('net1.bias', tensor([ 0.2742, 0.2194])),
('net2.weight', tensor([[[[ 0.2241, 0.2280, -0.0597],
[-0.1045, -0.1610, 0.0445],
[-0.1772, -0.0639, -0.0172]],

[[ 0.0975, -0.0081, 0.0690],
[-0.1273, 0.0693, 0.1792],
[ 0.0773, 0.1652, -0.1688]]],


[[[-0.2314, 0.0494, -0.0648],
[-0.1919, 0.2145, 0.0369],
[-0.1336, -0.1077, -0.0743]],

[[ 0.1510, -0.0868, -0.1766],
[-0.1764, 0.0398, 0.2146],
[-0.0269, 0.1241, -0.2304]]]])),
('net2.bias', tensor(1.00000e-02 *
[-7.3981, -0.8345]))])


temp = t.load('model_state_dict.pth')
OrderedDict([('net1.weight', tensor([[[[-0.3164, -0.2508, -0.3294],
[ 0.2388, -0.1582, 0.0678],
[ 0.0194, 0.1120, 0.2794]]],


[[[-0.2425, 0.0833, -0.0842],
[ 0.0687, -0.0637, -0.3034],
[-0.3268, -0.1049, -0.0286]]]])),
('net1.bias', tensor([ 0.2742, 0.2194])),
('net2.weight', tensor([[[[ 0.2241, 0.2280, -0.0597],
[-0.1045, -0.1610, 0.0445],
[-0.1772, -0.0639, -0.0172]],

[[ 0.0975, -0.0081, 0.0690],
[-0.1273, 0.0693, 0.1792],
[ 0.0773, 0.1652, -0.1688]]],


[[[-0.2314, 0.0494, -0.0648],
[-0.1919, 0.2145, 0.0369],
[-0.1336, -0.1077, -0.0743]],

[[ 0.1510, -0.0868, -0.1766],
[-0.1764, 0.0398, 0.2146],
[-0.0269, 0.1241, -0.2304]]]])),
('net2.bias', tensor(1.00000e-02 *
[-7.3981, -0.8345]))])

model2.state_dict()

OrderedDict([('net3.weight', tensor([[[[ 0.2793, -0.2330, 0.3270],
[-0.1419, 0.1562, 0.1875],
[-0.0249, 0.1297, 0.1642]]],


[[[ 0.2770, 0.1016, -0.1096],
[ 0.1929, 0.0210, 0.1722],
[ 0.1304, 0.0820, 0.1205]]]])),
('net3.bias', tensor([-0.3235, -0.1770])),
('net4.weight', tensor([[[[-0.2043, -0.1492],
[ 0.1728, -0.1069]],

[[-0.2903, 0.3385],
[ 0.2778, 0.1589]]],


[[[-0.1423, -0.0439],
[ 0.2849, -0.0840]],

[[ 0.0354, 0.1711],
[-0.0274, -0.2220]]]])),
('net4.bias', tensor([-0.0264, -0.1094]))])

model2.load_state_dict(temp)

Missing key(s) in state_dict: "net3.weight", "net3.bias", "net4.weight", "net4.bias".
Unexpected key(s) in state_dict: "net1.weight", "net1.bias", "net2.weight", "net2.bias".

# 印证了在保存模型参数的时候是根据名字进行保存,

# 保留模型
t.save(model,'model.pth')
temp2 = t.load('model.pth')
Nettest(
(net1): Conv2d(1, 2, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(net2): Sequential(
(0): Conv2d(2, 2, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
(1): Conv2d(1, 1, kernel_size=(3, 3), stride=(1, 1))
)
)
加载进来就是一个模型,包括forward什么的都还在。

numpy和list和tensor对于size的访问区别

  1. list: 只有len()方法,返回的是最外层的个数,reshape方法
  2. numpy: b.size是全部个数,b.shape是(2,3) b = np.arange(6).reshape(2,3), b.resize(2,3) np.arange(1,6,2)
  3. 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的普通索引基本共享内存,而高级索引基本不共享内存。
  4. numpy—>tensor t = t.from_numpy(numpy)(共享内存)或者 t = t.tensor(numpy)(返回新对象)
  5. tensor—>numpy np = t.numpy()(共享内存) 或者 np = np.array(t)
  6. numpy—>list list = np.tolist()(不共享内存)
  7. list—>numpy np = np.array(list)(不共享内存)
  8. tensor—>list list = t.tolist() (不共享内存) 或者 item = t.item() (不共享内存)
  9. list—>tensor t = t.tensor(list)(不共享内存)
    也就是说numpy和tensor可以做到互相共享内存,而list只是一个对外的和Python相连接的一个形式.
    补充:基于numpy和tensor,推荐使用shape属性, 修改形状则分别使用reshape()和view(),
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
import numpy as np
import torch as t

# a,b,c共享内存
a = np.ones([2,3])
b = t.from_numpy(a)
c = b.numpy()

# a,b,c不共享内存
a = np.ones([2,3])
b = t.tensor(a)
c = np.array(b)

import numpy as np
# 不共享内存
a = np.ones([2,3])
b = a.tolist()
c = np.array(b)

import tensor as t
a = t.tensor([2,3])
b = a.item()
b = a.tolist()
c = t.tensor(b)

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
26
In [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
19
In [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以执行该脚本文件。
使用三引号(‘’’或”””)可以指定一个多行字符串。