pytest快速入门

pytest快速入门

pytest
学习内容

%title插图%num

特点:

简答、已读
支持参数化
支持运行由unitest编写的测试Case
具有很多第三方插件,并且可以自定义扩展
支持重复执行失败的case
可以和持续集成工具集成
安装及快速入门
安装命令:pip3 install pytest

创建*个测试用例
#1.导入pytest包
import pytest
#2.测试用例方法
def func(x):
return x+1

def test001():
print(‘—–test001用例——-‘)
assert func(3) == 6 #断言失败

def test002():
print(‘——test002用例——–‘)
assert func(3) == 4 #断言成功

#3.执行
if __name__ == ‘__main__’:
pytest.main([“-vs”,”test_sample.py”])

pytest的前后置
(1)函数级别:setup、teardown

用于测试方法的始末
运行一次测试用例会运行一次setup和teardown
# 类之外
def test001():
print(“teat001用例_类外”)

def test002():
print(“test002用例_类外”)

def setup():
print(‘用例开始前执行’)

def teardown():
print(“用例后执行”)

if __name__ == ‘__main__’:
pytest.main([“-vs”,”test_method.py”])

运行结果:

%title插图%num

(2)类级别:setup_class、teardown_class

运行于测试类的始末
(3)类中方法级别

setup_method 、teardown_method
(4)模块级别(需放置类外):setup_module 、teardoen_module

所有模块开始始末
import pytest

def setup_module(self):
print(“模块开始前运行”)

def teardown_module(self):
print(“模块结束后运行”)

class Testclass():

def setup_class(self):
print(“类开始前运行”)

def teardown_class(self):
print(“类结束后运行”)

def setup_method(self):
print(“类中方法开始前运行”)

def teardown_method(self):
print(“类中方法结束后运行”)

def test001(self):
print(“test001用例——类中”)

def test002(self):
print(“test002用例——类中”)

def test003(self):
print(“test003用例——类中”)

if __name__ == ‘__main__’:
pytest.main([“-vs”,”test_class.py”])

运行结果:

%title插图%num
默认运行规则
测试文件以test_.py开头或以.test.py结尾
测试类以Test开头,并且不能带有__init__方法
测试函数以test_开头
自定义运行规则
文件名:pytest.ini(不可更改)
作用域:当前目录和其子目录下的所有case

#标识
[pytest]

#指定默认执行的命令
addopts = -vs

#指定执行case的目录,多个目录用空格隔开
testpaths=./testcase

#指定文件、类、方法的命名规则,多个用空格隔开
python_files = test_*.py
python_classes = Test_* Test*
python_functions = test_* test*

python之二分法

python之二分法
文章目录
python之二分法
一、什么是算法
二、二分法应用场景
示例
一、什么是算法
这里的算法就是基于函数递归的称述拓展

算法就是高效解决问题的方法
二分法就是一种算法
二、二分法应用场景
想要从一个从小到大排列的成千上万个值中找到指定的值
如果使用遍历的话效率太低
那么而二分法就可以*大的缩小问题的规模,以此来提高效率
示例
nums = [-23,-2,4,5,8,90,234,345,467,786,978,8900] # 从小到大排列
def check(num,l):
print(l)
if len(l) == 0:
print(“不存在这个值”)
return
mid_num = len(l) // 2
if num > l[mid_num]: # 说明在中间值得右边
l = l[mid_num+1:] # 使用切片将右边的值从新赋值给 l
check(num,l) # 递归
elif num < l[mid_num]: # 说明在中间值得右边
l = l[:mid_num] # 使用切片将右边的值从新赋值给 l
check(num,l) # 递归
else:
print(“OK!”)

check(8900,nums) # OK!

python基础知识点

python基础知识点

Python2.x 中使用 Python3.x 的 print 函数
from future import print_function #Python3.x 与 Python2.x 的许多兼容性设计的功能可以通过 future 这个包来导入

python 中多行注释使用三个单引号(’’’)或三个双引号(“””)。

Python 列表截取可以接收第三个参数
参数作用是截取的步长,以下实例在索引 1 到索引 4 的位置并设置为步长为 2(间隔一个位置)来截取字符串:

%title插图%num
python元组用 () 标识。内部元素用逗号隔开。但是元组不能二次赋值,相当于只读列表。

complex(real [,imag]) 创建一个复数
print(complex(1))
print(complex(‘2+1j’))
print(complex(2, 5))
l = [1, 3, 4, 5]
for i in l:
print(complex(i, 5))
结果输出如下:
(1+0j)
(2+1j)
(2+5j)
(1+5j)
(3+5j)
(4+5j)
(5+5j)

eval(str) 用来计算在字符串中的有效Python表达式,并返回一个对象
#字符串转换成列表
a = “[[1,2], [3,4], [5,6], [7,8], [9,0]]”
print(type(a))
b = eval(a)
print(b,type(b))
结果:
<class ‘str’>
([1, 2], [3, 4], [5, 6], [7, 8], [9, 0]) <class ‘list’>
#字符串转换成字典
a = “{1: ‘a’, 2: ‘b’}”
print(type(a))
b = eval(a)
print(b,type(b))
结果
<class ‘str’>
{1: ‘a’, 2: ‘b’} <class ‘dict’>

创建[] 是 list() 速度的的两倍 (Python3.9 版本)
import timeit
b = timeit.timeit(‘list()’, number=10**7)
print(b)
a = timeit.timeit(’[]’, number=10 ** 7)
print(a)
#了解原因
from dis import dis
dis(“[]”)
dis(“list()”)

dict(d) 创建一个字典,d 必须是一个序列 (key,value)元组。

frozenset(s) 转换为不可变集合

chr(x) 将一个整数转换为一个ASCII字符

协程

协程

目录
一、yield
1.实现
二、greenlet
1. 简介
2.用法
3.实现
三、gevent
1.简介
2.用法
3.实现
4.geventa的monkey模块
四、使用asyncio实现协程
1.格式
2.实现
3.aiohttp实现多任务异步协程
一、yield
协程是python个中另外一种实现多任务的方式,只不过比线程更小占用更小执行单元
1.实现
import time

def task_1():
while True:
print(“—1—-“)
time.sleep(0.1)
yield

def task_2():
while True:
print(“—2—-“)
time.sleep(0.1)
yield

def main():
t1 = task_1()
t2 = task_2()
# 先执行t1,当t1中遇到yield的时候,退出函数
# 然后执行t2,当它遇到yield的时候,再次切换到t1中
# 这样t1/t2/t1/t2的交替运行,*终实现了多任务….协程
while True:
next(t1)
next(t2)

if __name__ == “__main__”:
main()
二、greenlet
1. 简介
为了更好使用协程来完成多任务,python中的greenlet模块对其封装,从而使得切换任务变的更加简单。
需要人工切换
依赖:pip install greenlet
2.用法
from greenlet import greenlet

实例化greenlet对象
g = greenlet(func):
调度:
g.switch()
3.实现
from greenlet import greenlet
import time

def test1():
while True:
print(“—A–“)
gr2.switch() # 切换任务
print(‘延时0.5秒’)
time.sleep(0.5)

def test2():
while True:
print(“—B–“)
gr1.switch() # 切换任务
print(‘延时0.5秒’)
time.sleep(0.5)

gr1 = greenlet(test1)
gr2 = greenlet(test2)

# 切换到gr1中运行
gr1.switch()

三、gevent
1.简介
对greentlet的进一步封装
原理是当一个greenlet遇到IO(指的是input output 输入输出,比如网络、文件操作等)操作时,比如访问网络,就自动切换到其他的greenlet,等到IO操作完成,再在适当的时候切换回来继续执行。
由于IO操作非常耗时,经常使程序处于等待状态,有了gevent为我们自动切换协程,就保证总有greenlet在运行,而不是等待IO
依赖:pip install gevent
2.用法
import gevent

实例化对象:

g = gevent.spown(run=None, *args, **kwargs)
run:接收的是一个函数
*args, **kwargs:传递到函数中的参数
g.join():等待协程执行结束
同时实例化多个对象:

gevent.joinall(objects=None)
objects:包含实例化对象的列表
3.实现
import gevent
import time

# monkey.patch_all() # 将程序中用到的耗时操作的代码,换为gevent中自己实现的模块

def f1(n):
for i in range(n):
print(gevent.getcurrent(), i)
# time.sleep(0.5)
gevent.sleep(0.5) # 导入gevent自己模块的sleep

def f2(n):
for i in range(n):
print(gevent.getcurrent(), i)
# time.sleep(0.5)
gevent.sleep(0.5) # 导入gevent自己模块的sleep

def f3(n):
for i in range(n):
print(gevent.getcurrent(), i)
# time.sleep(0.5)
gevent.sleep(0.5) # 导入gevent自己模块的sleep

print(“—-1—“)
g1 = gevent.spawn(f1, 5)
print(“—-2—“)
g2 = gevent.spawn(f2, 5)
print(“—-3—“)
g3 = gevent.spawn(f3, 5)
print(“—-4—“)
g1.join()
print(‘g1 is ok’)
g2.join()
print(‘g2 is ok’)
g3.join()
print(‘g3 is ok’)

# gevent.joinall([
# gevent.spawn(f1, 5),
# gevent.spawn(f2, 5),
# gevent.spawn(f3, 5),
# ])
4.geventa的monkey模块
解决延时操作只能使用gevent中的延时操作问题
本质上将程序中用到的耗时操作的代码,换为gevent中自己实现的模块
monkey.patch_all()
今后导入延时模块可以使用time,当碰到延时操作时,会自动将程序中用到的耗时操作的代码,换为gevent中自己实现的模块。
四、使用asyncio实现协程
1.格式
import asyncio

1.async def func():

# 当有耗时操作的时候切换协程
await asyncio.sleep(x)

2.a = func():调用之后返回的就是一个协程对象

3.创建协程的时间循环对象:
loop = asyncio.get_event_loop()

4.创建task对象的两种方式:
task = loop.create_task(a)
task = asyncio.ensure_future(a)

5.执行task对象
loop.run_until_complete(asyncio.wait(fs))
fs:可迭代对象,封装了多个任务对象,一般为列表

2.实现
import asyncio
import time

async def request(url):
print(‘正在下载’, url)
# 在异步协程中如果出现了同步模块相关的代码,那么就无法实现异步。
# time.sleep(2)
# 当在asyncio中遇到阻塞操作必须进行手动挂起
await asyncio.sleep(2)
print(‘下载完毕’, url)

start = time.time()
urls = [
‘www.baidu.com’,
‘www.sogou.com’,
‘www.goubanjia.com’
]

# 任务列表:存放多个任务对象
loop = asyncio.get_event_loop()
stasks = []
for url in urls:
# 创建协程对象
c = request(url)
# 创建task对象
task = asyncio.ensure_future(c)
# task = loop.create_task(c)
# 追加到列表中
stasks.append(task)

# 需要将任务列表封装到wait中
loop.run_until_complete(asyncio.wait(stasks))

print(time.time() – start)

运行结果:

正在下载 www.baidu.com
正在下载 www.sogou.com
正在下载 www.goubanjia.com
下载完毕 www.baidu.com
下载完毕 www.sogou.com
下载完毕 www.goubanjia.com
2.0125160217285156

3.aiohttp实现多任务异步协程
上述中必须使用await asyncio.sleep(2)是因为它是基于异步的延时操作,使用time.sleep()是同步的延时操作,无法实现多任务并发执行
同理,requests.get是基于同步,必须使用基于异步的网络请求模块进行指定url的请求发送
aiohttp:基于异步网络请求的模块
依赖:pip install aiohttp
例:

# 使用该模块中的ClientSession
import requests
import asyncio
import time
import aiohttp # 安装包

start = time.time()

urls = [‘http://www.sougou.com’, ‘http://www.goubanjia.com’, ‘http://www.baidu.com’]
# for i in range(10):
# urls.append(‘http://www.baidu.com’)
print(urls)

async def get_page(url):
async with aiohttp.ClientSession() as session:
# get()、post():
# 还可以携带的参数:headers,params/data,proxy=’http://ip:port’
async with await session.get(url) as response:
# text()返回字符串形式的响应数据
# read()返回的二进制形式的响应数据
# json()返回的就是json对象
print(‘开始获取’, url)
# 注意:获取响应数据操作之前一定要使用await进行手动挂起
page_text = await response.text()
# print(‘结束获取’, page_text)
print(‘结束获取’, url)

tasks = []

loop = asyncio.get_event_loop()
for url in urls:
c = get_page(url)
task = asyncio.ensure_future(c)
tasks.append(task)

loop.run_until_complete(asyncio.wait(tasks))

end = time.time()

print(‘总耗时:’, end – start)

执行结果:

[‘http://www.sougou.com’, ‘http://www.goubanjia.com’, ‘http://www.baidu.com’]
开始获取 http://www.baidu.com
开始获取 http://www.goubanjia.com
结束获取 http://www.goubanjia.com
结束获取 http://www.baidu.com
开始获取 http://www.sougou.com
结束获取 http://www.sougou.com
总耗时: 0.3390941619873047

高级特性:迭代器

高级特性:迭代器

文章大部分参考来源:No-Coder’s Blog
1. 可迭代对象
我们已经知道可以对list、tuple、str等类型的数据使用for…in…的循环语法从其中依次拿到数据进行使用,我们把这样的过程称为遍历,也叫迭代。

但是,是否所有的数据类型都可以放到for…in…的语句中,然后让for…in…每次从中取出一条数据供我们使用,即供我们迭代吗?

#!/usr/bin/env python2.7
# -*- coding=utf-8 -*-

for i in 100:
print i

# >>> TypeError: ‘int’ object is not iterable
# int类型的对象是不可迭代的

class MyList(object):
def __init__(self):
self.names = []

def add(self, value):
self.names.append(value)

mylist = MyList()
mylist.add(‘1’)
mylist.add(‘2’)
mylist.add(‘3’)

for i in mylist:
print i

# >>> TypeError: ‘MyList’ object is not iterable
# MyList类型的对象是不可迭代的

2. 如何判断一个对象是否可迭代
“””
可以使用isinstance来判断对象是否为可迭代的
“””

from collections import Iterable

isinstance([], Iterable)
# True

isinstance({}, Iterable)
# True

isinstance(‘abc’, Iterable)
# True

isinstance(mylist, Iterable)
# False

isinstance(100, Iterable)
# False
3. 可迭代对象的本质
“”“
让我们来看下能够被for…in循环取值的类型到底都有什么相同的特性?
使用dir发现list tuple dict 这些数据类型都有一个函数叫__iter__函数是不是实现了这个函数 我们对应创建的内容就是可迭代的
”“”

class MyList(object):
def __init__(self):
self.names = []

def add(self, value):
self.names.append(value)

def __iter__(self):
pass

mylist = MyList()
mylist.add(‘1’)
mylist.add(‘2’)
mylist.add(‘3’)

for i in mylist:
print i

# >>> TypeError: iter() returned non-iterator of type ‘NoneType’
# MyList类型的对象iter函数返回的不是关于iterator的对象
# 那我们再去修改一下

class MyList(object):
def __init__(self):
self.names = []

def add(self, value):
self.names.append(value)

def __iter__(self):
return MyIterator(self)

class MyIterator(object):
def __init__(self, mylist):
self.mylist = mylist
self.current = 0

def __next__(self):
if self.current < len(self.mylist.container):
item = self.mylist.container[self.current]
self.current += 1
return item
else:
raise StopIteration

mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)
for i in mylist:
print(i)

# 1 2 3
# 成功我们先不管MyIterator是什么,我们目前关心的是只要对应的对象中实现了iter并且返回了对应的迭代器对象这个时候我们实现的对象就可以称之为可迭代的

4. iter()以及next()
li_iter = iter(li)
next(li_iter)
# 11
next(li_iter)
# 22
next(li_iter)
# 33
next(li_iter)
# 44
next(li_iter)
# 55
next(li_iter)
Traceback (most recent call last):
File “<stdin>”, line 1, in <module>
StopIteration

“””
list、tuple等都是可迭代对象,我们可以通过iter()函数获取这些可迭代对象的迭代器。然后我们可以对获取到的迭代器不断使用next()函数来获取下一条数据。iter()函数实际上就是调用了可迭代对象的__iter__方法。而__iter__方法则返回包含next函数的迭代器对象,然后我们使用迭代器对象的next方法不停的取出下一个值,直到raise为止
“””
5. 如何判断一个对象是否为迭代器
from collections import Iterator

isinstance([], Iterator)
# False

isinstance(iter([]), Iterator)
# True

isinstance(iter(“abc”), Iterator)
# True
6. 迭代器iterator
“””
通过上面的分析,我们已经知道,迭代器是用来帮助我们记录每次迭代访问到的位置,当我们对迭代器使用next()函数的时候,迭代器会向我们返回它所记录位置的下一个位置的数据。实际上,在使用next()函数的时候,调用的就是迭代器对象的__next__方法(Python3中是对象的__next__方法,Python2中是对象的next()方法)。所以,我们要想构造一个迭代器,就要实现它的__next__方法。但这还不够,python要求迭代器本身也是可迭代的,所以我们还要为迭代器实现__iter__方法,而__iter__方法要返回一个迭代器,迭代器自身正是一个迭代器,所以迭代器的__iter__方法返回自身即可。
总结来说:一个实现了__iter__方法和__next__方法的对象,就是迭代器。
“””

class MyList(object):

def __init__(self):
self.container = []

def add(self, item):
self.container.append(item)

def __iter__(self):
“””返回一个迭代器”””
return MyIterator(self)

class MyIterator(object):

def __init__(self, mylist):
self.mylist = mylist
self.current = 0

def __next__(self):
if self.current < len(self.mylist.container):
item = self.mylist.container[self.current]
self.current += 1
return item
else:
raise StopIteration

if __name__ == “__main__”:
mylist = MyList()
mylist.add(1)
mylist.add(2)
mylist.add(3)

for i in mylist:
print(i)
7. for…..in的本质
for item in items  循环的本质就是先通过iter()函数获取可迭代对象Iterable的迭代器Iterator,然后对获取到的迭代器不断调用next()方法来获取下一个值并将其赋值给item,当遇到StopIteration的异常后循环结束。

8. 迭代器简单的练习题
# 斐波那契实现

class Feb(object):
def __init__(self,num):
self.num = num
self.index = 0
self.a = 0
self.b = 1

def __iter__(self):
return self

def next(self):
if self.index < self.num:
v = self.a
self.a, self.b = self.a + self.b, self.a
self.index += 1
return v

else:
raise StopIteration

if __name__ == ‘__main__’:
f = Feb(20)
for i in f:
print i
# 倒叙取值

class Reverse(object):

def __init__(self,list):
self.num = len(list)
self.target = list

def __iter__(self):
return self

def next(self):
self.num -= 1
if self.num >= 0:
return self.target[self.num]
else:
raise StopIteration

if __name__ == ‘__main__’:
list = [1, 2, 3, 4, 5, 6, 7, 8]
r = Reverse(list)
for i in r:
print i
学习到这我们总结一下:

可迭代对象(实现了iter方法,iter方法返回迭代器对象)

迭代器对象(实现了iter以及next方法)

python:序列类型及方法笔记!

python:序列类型及方法笔记!

序列类型

# 所谓序列,指的是一块可以存放多个值的连续内存空间,可以通过每个值所在的编号(索引)去访问他们
1.列表 list
定义 []
可变类型
#举例说明:

list1 = [‘大盘鸡’, ‘辣子鸡’, ‘羊肉串’, ‘小白菜’, ‘辣椒炒肉’, ‘土豆丝’]

print(type(list1))
列表名.方法名()

直接根据索引查找单个值

print(list1[5])
切片 查找列表当中的一段值 [起始值:终止值:步长]
#实例说明:

print(list1[2:5]) # 左闭右开实例说明:
print(list1[:5]) # 起始值不写 从0开始
print(list1[2:]) # 终止值不写 取到末尾
print(list1[2:5:3]) # 步长
print(list1[::3]) # 步长
index(元素,起始值,终止值) 查找元素的索引值 左闭右开
#实例说明:

print(list1.index(‘小白菜’))
print(list1.index(‘小白菜’, 2, 5))
print(list1.index(‘小白菜’, 3, 5))
count(元素) 计算列表中该元素出现的次数
#实例说明:

print(list1.count(‘小白菜’))
list2 = [‘hello’, ‘hello’, ‘hello’, ‘hello’]
print(list2.count(‘hello’))

append(元素) 往列表末尾追加一个元素
#实例说明:

list1.append(‘爆炒牛肚’)
print(list1)
insert(索引,元素) 往指定索引位置插入一个元素
#实例说明:

list1.insert(0, ‘小龙虾’)
print(list1)
extend(可迭代对象) 往列表当中添加多个元素:
#实例说明:

list1.extend([‘鸡蛋’, ‘豆腐’, ‘牛奶’])
print(list1)

直接指定索引进行修改
#实例说明:

list1[8] = ‘西红柿炒鸡蛋’
print(list1)
reverse 反序
#实例说明:

list1.reverse()
print(list1)
list2 = [1, 5, 3, 8]
sotr 排序
#实例说明:

list2.sort(reverse=True)
print(list2)
删除
pop 没有参数的时候删除的是*后一个元素
#实例说明:

list1.pop()
print(list1)
pop(索引) 根据索引删除指定位置的元素
#实例说明:

list1.pop(1)
print(list1)
remove(元素) 删除指定的元素
#实例说明:

list1.remove(‘牛奶’)
print(list1)
del 不是列表独有的方法
#实例说明:

del list1[0]
print(list1)
del list1[1:4] # 切片删除多个元素
print(list1)
clear 清空整个列表
#实例说明:

list1.clear()
print(list1)
print(dir(list1))
2.元组 tuple
定义 ()
不可变类型

tuple1 = (‘九千亿少女的梦’, ‘秋名山车神’)
print(type(tuple1))
tuple2 = (1, ) # 只有一个元素的时候 需要加逗号
print(type(tuple2))

直接根据索引进行查

print(tuple1[1])
index(元素,起始值,终止值) 根据元素查找索引

print(tuple1.index(‘九千亿少女的梦’))
切片 与列表一致

print(tuple1[:])
conut(元素) 查询元素的个数

print(tuple1.count(‘九千亿少女的梦’))
元组类型转成列表类型

print(list(tuple1))
列表类型转成元组类型

print(tuple(list2))
del 删

del tuple1
print(tuple1) 已经不存在 会保存
del list1
print(list1)
3.字符串 str
定义 ‘’ “” ‘’’’’’
不可变类型

str1 = ‘黄河之水天上来,奔流到海不复回’
print(type(str1)) # 查看类型

直接根据索引查

print(str1[8])
index(元素,起始值,终止值) 查找元素的索引

print(str1.index(‘来’, 5, 8)) # 如果没找到 会报错
find(元素,起始值,终止值) 查找元素的索引

print(str1.find(‘来’, 7, 8)) # 如果没找到 返回-1
切片

print(str1[0:4])

replace(旧元素,新元素)

str2 = ‘天生我材必有用’
print(id(str2))
str3 = str2.replace(‘我’, ‘你’) # 重生
print(str2)
print(id(str2))
print(id(str3))
print(str3)

str3 = ‘hello world’
print(str3.upper()) # 变大写

str4 = ‘HELLO WORLD’
print(str4.lower()) # 变小写
strip 去掉空格

str5 = ‘ a b c ‘
print(str5.strip())
split 按照参数进行分割

str6 = ‘真正的勇士,敢于直面惨淡的人生,敢于正视淋漓的鲜血’
print(str6.split(‘,’))
print(str6.split(‘敢于’))
字符串的格式化输出

str1 = ‘人生得意须尽欢’
str2 = ‘莫使金樽空对月’
str3 = ‘天生我材必有用’
” + “直接相加

print(str1+str2+str3)
join

print(”.join([str1, str2, str3]))
print(‘ ‘.join([str1, str2, str3]))
print(‘哇塞’.join([str1, str2, str3]))
print(‘,’.join([str1, str2, str3]))
format

print(‘{} 哇哈哈哈 {}’.format(str1, str2))
print(‘{1} {0}’.format(str1, str2))
占位符 %s

name = ‘橗釉’
age = 18
print(‘大家好,我是%s, 我今年%s岁’ % (name, age))
字符串的转义 加了 \ 字符不再表示它本身的含义

print(‘hello \n python’) # \n代表换行
print(‘hello \t python’) # \t代表tab
字符串的反转义 r

print(r’hello \n python’)

深度学习 | Tensorflow2.0使用心得

深度学习 | Tensorflow2.0使用心得

Tensorflow2.0使用心得
文章目录
Tensorflow2.0使用心得
Keras
一、Dataset加载数据
1.0 设定超参数
1.1 从csv读取
1.2 从npz读取
二、搭建网络结构
三、损失函数与评估构建
3.1 损失函数
3.2 评估函数
四、优化函数构建
4.1 构建优化器
4.2 优化函数构建
五、开始迭代
六、评估结果
Keras
Tensorflow2推荐使用keras构建网络,常见的神经网络都包含在keras.layer中

Keras 是一个用于构建和训练深度学习模型的高阶 API。它可用于快速设计原型、高级研究和生产。

keras的3个优点: 方便用户使用、模块化和可组合、易于扩展

import tensorflow as tf
from tensorflow.keras import layers
print(tf.version)
print(tf.keras.version)

一、Dataset加载数据
Tensorflow2推荐使用Dataset加入数据。数据的格式为:numpy.ndarray

1.0 设定超参数
# MNIST数据集
num_classes = 10 # 0到9总共10个数字
num_features = 784 # 28*28

# 设定训练超参数
learning_rate = 0.1 # 学习率
training_steps = 2000 # 迭代步数
batch_size = 256 # 一批数据的大小
display_step = 100 # 展示间隔步数

# 神经网络超参数
n_hidden_1 = 128 # 第1层神经网络隐层的神经元个数
n_hidden_2 = 256 # 第2层神经网络隐层的神经元个数
1.1 从csv读取
csv文件,笔者个人建议先利用pandas进行特征工程的创建,然后再将pandas.DataFrame中的数据以values的形式提取出来,导入到Tensorflow中的Dataset。

import tensorflow as tf
import pandas as pd
import numpy as np
from tensorflow.keras import Model, layers

#train, test Dataset
file_train_path = r’./mnist_train.csv’
file_test_path = r’./mnist_test.csv’

# Pandas读取csv
df_train = pd.read_csv(file_train_path)
df_test = pd.read_csv(file_test_path)

# Pandas提取特征与标签,并转为ndarray
x_train = df_train.drop(columns = [‘5’]).values
y_train = df_train[‘5’].values
x_test = df_test.drop(columns = [‘7’]).values
y_test = df_test[‘7′].values

# 将ndarray数据导入Dataset
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.repeat().shuffle(5000).batch(batch_size).prefetch(1)
1.2 从npz读取
部分数据集会将数据以npz的形式存储,这是numpy保存的数据格式,加载后的数据均为ndarray格式,使用方法如下:

import tensorflow as tf
import numpy as np
from tensorflow.keras import Model, layers
# 加载npz数据集
mnist_np = np.load(r’./mnist.npz’)

# 创建训练集,测试集
(x_train,y_train),(y_test,y_test) = (mnist_np[‘x_train’],mnist_np[‘y_train’]),(mnist_np[‘x_test’],mnist_np[‘y_test’])
#执行完这一步,建议查看一下数据的shape
x_train, x_test = x_train.reshape([-1, num_features]), x_test.reshape([-1, num_features])
# 把[0, 255]范围的像素输入幅度缩放到[0, 1].
x_train, x_test = x_train / 255., x_test / 255.

# 将ndarray数据导入Dataset
train_data = tf.data.Dataset.from_tensor_slices((x_train, y_train))
train_data = train_data.repeat().shuffle(5000).batch(batch_size).prefetch(1)
二、搭建网络结构
# 构建TF网络模型类
class NeuralNet(Model):
# 设定层次
def __init__(self):
super(NeuralNet, self).__init__() #super表继承
# 第1个全连接层,相当于添加一个层
self.fc1 = layers.Dense(n_hidden_1, activation=tf.nn.relu) #n_hidden_1 = 128 # 第1层神经网络隐层的神经元个数
# 第2个全连接层,相当于添加一个层
self.fc2 = layers.Dense(n_hidden_2, activation=tf.nn.relu) #n_hidden_2 = 256 # 第2层神经网络隐层的神经元个数
# 输出层
self.out = layers.Dense(num_classes)

# 前向传播,调用call方法
def call(self, x, is_training=False):
x = self.fc1(x) #input: x
x = self.fc2(x)
x = self.out(x)
if not is_training:
# 训练阶段要计算交叉熵的函数需要,拿到softmax归一化之前得分
x = tf.nn.softmax(x)
return x

# 构建神经网络
neural_net = NeuralNet()
三、损失函数与评估构建
3.1 损失函数
分类问题中,常用交叉熵作为损失函数。

# 交叉熵损失
def cross_entropy_loss(x, y):
# 把label转成int64类型
y = tf.cast(y, tf.int64) #或者用y = np.array(y, np.int64)
# 应用sparse_softmax_cross_entropy_with_logits对未归一化之前的得分计算交叉熵
loss = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=y, logits=x)
# 求一个batch数据上的平均loss
return tf.reduce_mean(loss)
关于交叉熵损失函数,主要具备两种形态:

tf.nn.sparse_softmax_cross_entropy_with_logits
tf.nn.softmax_cross_entropy_with_logits
sparse_softmax_cross_entropy_with_logits中 labels接受直接的数字标签
如[1], [2], [3], [4] (类型只能为int32,int64),

而softmax_cross_entropy_with_logits中的label只能接收One-hot后的标签,如[1,0,0,0], [0,1,0,0],[0,0,1,0], [0,0,0,1] (类型为int32, int64)

相当于sparse_softmax_cross_entropy_with_logits 对标签多做一个one-hot动作
详情可见此链接
https://blog.csdn.net/yxq5997/article/details/83033843

3.2 评估函数
# 准确率
def accuracy(y_pred, y_true):
# tf.argmax(y_pred, 1)把每一行的*大元素的索引记录下来
correct_prediction = tf.equal(tf.argmax(y_pred, 1), tf.cast(y_true, tf.int64))
return tf.reduce_mean(tf.cast(correct_prediction, tf.float32), axis=-1)
四、优化函数构建
4.1 构建优化器
优化器常使用随机梯度下降

# 设定优化器为随机梯度下降
optimizer = tf.keras.optimizers.SGD(learning_rate)
4.2 优化函数构建
def run_optimization(x, y):
# tf 2.0的写法,把prediction和loss都写到GradientTape中,以便自动微分
with tf.GradientTape() as g:
# 前向传播(正向传播)
pred = neural_net(x, is_training=True)
# 计算损失
loss = cross_entropy_loss(pred, y)

# 需要更新的变量
trainable_variables = neural_net.trainable_variables

# 计算梯度
gradients = g.gradient(loss, trainable_variables)

# 基于梯度更新W和b
optimizer.apply_gradients(zip(gradients, trainable_variables))
五、开始迭代
for step, (batch_x, batch_y) in enumerate(train_data.take(training_steps), 1):
# 优化
run_optimization(batch_x, batch_y)

if step % display_step == 0:
pred = neural_net(batch_x, is_training=True)
loss = cross_entropy_loss(pred, batch_y)
acc = accuracy(pred, batch_y)
print(“step: %i, loss: %f, accuracy: %f” % (step, loss, acc))
六、评估结果
pred = neural_net(x_test, is_training=False)
print(“Test Accuracy: %f” % accuracy(pred, y_test))

 

DRF基本源码、Resquest及Response对象

DRF基本源码、Resquest及Response对象

1、CBV(Class Base Views)
思路–路由层–as——view()内的闭包函数内存地址
path(‘test/’,views.TestView.as_view())
as_view()
@classonlymethod
def as_view(cls, **initkwargs):
#1、内部有view函数、并且有着对外层函数的引用 cls
# return view *后返回内层函数名、说明是个闭包函数
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, ‘get’) and not hasattr(self, ‘head’):
self.head = self.get
self.setup(request, *args, **kwargs)

view.view_class = cls
view.view_initkwargs = initkwargs

# take name and docstring from class
update_wrapper(view, cls, updated=())

# and possible attributes set by decorators
# like csrf_exempt from dispatch
update_wrapper(view, cls.dispatch, assigned=())
return view
#2、django任务启动的时候、path(‘test/’,views.TestView.as_view())产生变形
path(‘test/’,views.view)
views内存地址对应
def view(request, *args, **kwargs):
self = cls(**initkwargs)
if hasattr(self, ‘get’) and not hasattr(self, ‘head’):
self.head = self.get
self.setup(request, *args, **kwargs)

return self.dispatch(request, *args, **kwargs)
#3、本质是在执行self.dispatch
def dispatch(self, request, *args, **kwargs):
#4、*终通过反射getattr去获得方法
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(), self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
#5、执行get方法,传入参数
return handler(request, *args, **kwargs)

小结
CBV通过View类as_view()内的闭包函数view的内存地址
执行dispatch通过反射、判断post,get请求
2、APIView的源码、执行流程
from rest_framework.views import APIView
#django内部–APIView继承了View
class APIView(View):
settings = api_settings
schema = DefaultSchema()
@classmethod
def as_view(cls, **initkwargs):
# super()对父类as_view()的调用
#1、APIView类的as_view内部使用的是 View 内部的 as_view内的view闭包函数
view = super().as_view(**initkwargs)
view.cls = cls
view.initkwargs = initkwargs
#2、请求匹配成功执行View类的as_view()内的view内存地址、但是
#返回值增加了 csrf_exempt装饰、所以继承APIView的接口都无需csrf校验
return csrf_exempt(view)

说明:
drf对view的dispatch进行了重写
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
#所以drf中的request已经不是django中的reqeust了,而是drf自己的request
3、Request对象分析
class Request:
def __init__(self, request, parsers=None, authenticators=None,
negotiator=None, parser_context=None):
assert isinstance(request, HttpRequest), (
‘The `request` argument must be an instance of ‘
‘`django.http.HttpRequest`, not `{}.{}`.’
.format(request.__class__.__module__, request.__class__.__name__)
)
self._request = request #原生的request
self.parsers = parsers or ()
self.authenticators = authenticators or ()
self.negotiator = negotiator or self._default_negotiator()
self.parser_context = parser_context
self._data = Empty
self._files = Empty
self._full_data = Empty
self._content_type = Empty
self._stream = Empty

def __getattr__(self, attr):
try:
#重写了getattr、 通过反射,将原生request对象,以及属性和方法取出
return getattr(self._request, attr)
except AttributeError:
return self.__getattribute__(attr)

”’query_params方法被@property装饰器将方法封装成属性
get请求的数据都在这里取
”’
@property
def query_params(self):
“””
More semantically correct name for request.GET.
“””
return self._request.GET

”’
通过@property装饰器将data方法封装成属性
data方法:它是一个字典,post请求不管使用什么编码,传过来的数据,都在request.data
”’
@property
def data(self):
if not _hasattr(self, ‘_full_data’):
self._load_data_and_files()
return self._full_data

#文件的数据
@property
def FILES(self):
# Leave this one alone for backwards compat with Django’s request.FILES
# Different from the other two cases, which are not valid property
# names on the WSGIRequest class.
if not _hasattr(self, ‘_files’):
self._load_data_and_files()
return self._files
总结:

-虽然视图类中request对象变成了drf的request,但是用起来,跟原来的一样,只不过它多了一些属性
-request.data #post请求提交的数据,不论什么格式,都在它中取出来
-requst.query_params# get请求提交的数据(查询参数)
注意:请求头是存放在request.META中,获取请求头的信息可以从该属性中获取
4、Response对象源码分析
from rest_framework.response import Response

class Response(SimpleTemplateResponse):
“””
An HttpResponse that allows its data to be rendered into
arbitrary media types.
“””

def __init__(self, data=None, status=None,
template_name=None, headers=None,
exception=False, content_type=None):
#data: 要返回的数据–字典
#status: 返回的状态码、默认200
#template_name: 渲染的template模板名、可自定制
#headers: 响应头、可以放东西
#content_type: 响应编码格式 application/json和text/html
注意:from rest_framework import status
在stauts模块下、所用到的状态码都被定义成了常量
响应数据数据格式配置。
-局部使用:对某个视图类有效
-在视图类中写如下
from rest_framework.renderers import JSONRenderer
renderer_classes=[JSONRenderer,]-全局使用:全局的视图类,所有请求,都有效
-在setting.py中加入如下
REST_FRAMEWORK = {
‘DEFAULT_RENDERER_CLASSES’: ( # 默认响应渲染类
‘rest_framework.renderers.JSONRenderer’, # json渲染器
‘rest_framework.renderers.BrowsableAPIRenderer’, # 浏览API渲染器
)
}
5、对Response对象的重新封装
from rest_framework.response import Response
class APIResponse(Response):
def __init__(self,code=100,msg=’成功’,data=None,status=None,headers=None,**kwargs):
dic = {‘code’: code, ‘msg’: msg}
if data:
dic = {‘code’: code, ‘msg’: msg,’data’:data}
dic.update(kwargs)
super().__init__(data=dic, status=status,headers=headers)

pytorch 状态字典:state_dict使用详解

pytorch 状态字典:state_dict使用详解

 

 

竞赛

数据科学竞赛(大数据竞赛,机器学习竞赛,人工智能算法竞赛)已经成为各大知名互联网企业征集解决方案和选拔人才的*选择,很多同学为了拿到大厂offer,纷纷加入了数据竞赛的浪潮之中。

浪子私房菜

¥29.90

订阅博主

pytorch 中的 state_dict 是一个简单的python的字典对象****,将每一层与它的对应参数建立映射关系.(如model的每一层的weights及偏置等等)

 

(注意,只有那些参数可以训练的layer才会被保存到模型的state_dict中,如卷积层,线性层等等)

 

优化器对象Optimizer也有一个state_dict,它包含了优化器的状态以及被使用的超参数(如lr, momentum,weight_decay等)

 

备注:

 

state_dict是在定义了model或optimizer之后pytorch自动生成的,可以直接调用.常用的保存state_dict的格式是”.pt”或’.pth’的文件,即下面命令的 PATH=”./***.pt”

torch.save(model.state_dict(), PATH)

load_state_dict 也是model或optimizer之后pytorch自动具备的函数,可以直接调用

model = TheModelClass(*args, **kwargs)

model.load_state_dict(torch.load(PATH))

model.eval()

 

注意:model.eval() 的重要性,在2)中*后用到了model.eval(),是因为,只有在执行该命令后,”dropout层”及”batch normalization层”才会进入 evalution 模态. 而在”训练(training)模态”与”评估(evalution)模态”下,这两层有不同的表现形式.

 

模态字典(state_dict)的保存(model是一个网络结构类的对象)

 

1.1)仅保存学习到的参数,用以下命令

 

torch.save(model.state_dict(), PATH)

1.2)加载model.state_dict,用以下命令

 

model = TheModelClass(*args, **kwargs)

model.load_state_dict(torch.load(PATH))

model.eval()

备注:model.load_state_dict的操作对象是 一个具体的对象,而不能是文件名

 

2.1)保存整个model的状态,用以下命令

 

torch.save(model, PATH)

2.2)加载整个model的状态,用以下命令:

 

model = torch.load(PATH)

mode.eval()

state_dict 是一个python的字典格式,以字典的格式存储,然后以字典的格式被加载,而且只加载key匹配的项

 

如何仅加载某一层的训练的到的参数(某一层的state)

 

If you want to load parameters from one layer to another, but some

keys do not match, simply change the name of the parameter keys in the

state_dict that you are loading to match the keys in the model that

you are loading into.

 

conv1_weight_state = torch.load(‘./model_state_dict.pt’)[‘conv1.weight’]

加载模型参数后,如何设置某层某参数的”是否需要训练”(param.requires_grad)

 

for param in list(mode.pretrained.parameters()):

param.requires_grad = False

注意: requires_grad的操作对象是tensor.

 

疑问:能否直接对某个层直接之用requires_grad呢?例如:model.conv1.requires_grad=False

 

回答:经测试,不可以.model.conv1 没有requires_grad属性.

 

全部测试代码:

 

#-*-coding:utf-8-*-

import torch

import torch.nn as nn

import torch.nn.functional as F

import torch.optim as optim

 

 

 

# define model

class TheModelClass(nn.Module):

def __init__(self):

super(TheModelClass,self).__init__()

self.conv1 = nn.Conv2d(3,6,5)

self.pool = nn.MaxPool2d(2,2)

self.conv2 = nn.Conv2d(6,16,5)

self.fc1 = nn.Linear(16*5*5,120)

self.fc2 = nn.Linear(120,84)

self.fc3 = nn.Linear(84,10)

 

def forward(self,x):

x = self.pool(F.relu(self.conv1(x)))

x = self.pool(F.relu(self.conv2(x)))

x = x.view(-1,16*5*5)

x = F.relu(self.fc1(x))

x = F.relu(self.fc2(x))

x = self.fc3(x)

return x

 

# initial model

model = TheModelClass()

 

#initialize the optimizer

optimizer = optim.SGD(model.parameters(),lr=0.001,momentum=0.9)

 

# print the model’s state_dict

print(“model’s state_dict:”)

for param_tensor in model.state_dict():

print(param_tensor,’\t’,model.state_dict()[param_tensor].size())

 

print(“\noptimizer’s state_dict”)

for var_name in optimizer.state_dict():

print(var_name,’\t’,optimizer.state_dict()[var_name])

 

print(“\nprint particular param”)

print(‘\n’,model.conv1.weight.size())

print(‘\n’,model.conv1.weight)

 

print(“————————————“)

torch.save(model.state_dict(),’./model_state_dict.pt’)

# model_2 = TheModelClass()

# model_2.load_state_dict(torch.load(‘./model_state_dict’))

# model.eval()

# print(‘\n’,model_2.conv1.weight)

# print((model_2.conv1.weight == model.conv1.weight).size())

## 仅仅加载某一层的参数

conv1_weight_state = torch.load(‘./model_state_dict.pt’)[‘conv1.weight’]

print(conv1_weight_state==model.conv1.weight)

 

model_2 = TheModelClass()

model_2.load_state_dict(torch.load(‘./model_state_dict.pt’))

model_2.conv1.requires_grad=False

print(model_2.conv1.requires_grad)

print(model_2.conv1.bias.requires_grad)

 

 

Python 对象与 JSON 字符串的相互转换

Python 对象与 JSON 字符串的相互转换

JSON 简介
JSON(JavaScript Object Notation)
是一种轻量级的数据交换格式,它使得人们很容易的进行阅读和编写。同时也方便了机器进行解析和生成。适用于进行数据交互的场景,比如网站前台与后台之间的数据交互。

json 简单说就是 javascript 中的对象和数组,所以这两种结构就是对象和数组两种结构,通过这两种结构可以表示各种复杂的结构。

对象: 对象在 js 中表示为{ }括起来的内容,数据结构为 { key:value, key:value, … }的键值对的结构,在面向对象的语言中,key 为对象的属性,value 为对应的属性值,所以很容易理解,取值方法为 对象.key 获取属性值,这个属性值的类型可以是数字、字符串、数组、对象这几种。

数组: 数组在 js 中是中括号[ ]括起来的内容,数据结构为 [“Python”, “javascript”, “C++”, …],取值方式和所有语言中一样,使用索引获取,字段值的类型可以是数字、字符串、数组、对象几种。

Python 中的 json 模块
Python 中自带了 json 模块,直接 import json 就可以使用了。

json 模块提供了四个功能:dumps、dump、loads、load,用于字符串和 python 数据类型间进行转换。

Python 字典(dict)和 JSON 字符串的区别
Python 的字典是一种数据结构,json 是一种数据传输格式及表现形式。

字典的 key 值只要能 hash 即可,而 json 必须是字符串。

json 格式的数据,在 python 中以字符串形式呈现

json 中的空置为 null,字典中的空值为 None

json 中的 key 不论是数字还是字符串都要用双引号括起来(key 可以重复)

python 中的字典 key 为数字时用不用引号括起来都可以(key 不能重复)

json 里面类似 dict 里面的键可以重复,转换成字典之后,后面的会将前面的覆盖,因为 dict 里面的键不能重复

dict 里可以嵌套 tuple,json 里只有 array。

json.dumps({1:2}) 的结果是 {“1”: 2};
json.dumps((1,2)) 的结果是 [1,2]
Python 中 JSON 模块的方法
1.json.loads()
把 json 格式字符串解码转换成 Python 对象,从 json 到 python 的类型转化对照如下:

import json

strList = ‘[1, 2, 3, 4]’
strDict = ‘{“city”: “北京”, “name”: “范爷”}’
json.loads(strList)
# [1, 2, 3, 4]
json.loads(strDict) # json 数据自动按 Unicode 存储
# {u’city’: u’\u5317\u4eac’, u’name’: u’\u5927\u732b’}
2.json.dumps()
实现 python 类型转化为 json 字符串,返回一个 str 对象把一个 Python 对象编码转换成 json 字符串

从 python 字典类型向 json 类型的转化对照如下:

import json

listStr = [1, 2, 3, 4]
tupleStr = (1, 2, 3, 4)
dictStr = {“city”: “北京”, “name”: “范爷”}

json.dumps(listStr)
# ‘[1, 2, 3, 4]’
json.dumps(tupleStr)
# ‘[1, 2, 3, 4]’

# 注意:json.dumps() 序列化时默认使用的 ascii 编码
# 添加参数 ensure_ascii=False 禁用 ascii 编码,按 utf-8 编码

json.dumps(dictStr)
# ‘{“city”: “\\u5317\\u4eac”, “name”: “\\u5927\\u5218”}’

print(json.dumps(dictStr, ensure_ascii=False))
# {“city”: “北京”, “name”: “范爷”}
3.json.dump()
将 Python 内置类型序列化为 json 对象后写入文件:

import json

listStr = [{“city”: “北京”}, {“name”: “范爷”}]
json.dump(listStr, open(“listStr.json”, “w”), ensure_ascii=False)

dictStr = {“city”: “北京”, “name”: “范爷”}
json.dump(dictStr, open(“dictStr.json”, “w”), ensure_ascii=False)
4.json.load()
读取文件中 json 形式的字符串元素转化成 python 类型:

import json

strList = json.load(open(“listStr.json”))
print(strList)

# [{u’city’: u’\u5317\u4eac’}, {u’name’: u’\u5927\u5218′}]

strDict = json.load(open(“dictStr.json”))
print(strDict)
# {u’city’: u’\u5317\u4eac’, u’name’: u’\u5927\u5218′}
注意事项
json.loads() 是把 Json 格式字符串解码转换成 Python 对象,如果在 json.loads的时候出错,要注意被解码的
Json 字符的编码。
如果传入的字符串的编码不是 UTF-8 的话,需要指定字符编码的参数 encoding

dataDict = json.loads(jsonStrGBK);
dataJsonStr 是 JSON 字符串,假设其编码本身是非 UTF-8 的话而是 GBK 的,那么上述代码会导致出错,改为对应的:
dataDict = json.loads(jsonStrGBK, encoding=”GBK”);
如果 dataJsonStr 通过 encoding 指定了合适的编码,但是其中又包含了其他编码的字符,则需要先去将 dataJsonStr 转换为 Unicode,然后再指定编码格式调用 json.loads()
dataJsonStrUni = dataJsonStr.decode(“GB2312″);
dataDict = json.loads(dataJsonStrUni, encoding=”GB2312”);