Skip to content

Latest commit

 

History

History
947 lines (864 loc) · 58.3 KB

实习学习计划.md

File metadata and controls

947 lines (864 loc) · 58.3 KB

额外学习计划

学习备忘录

-[ ] 深度学习算法再思考

  • 什么是fineturned

  • 最进邻算法(knn)原理实现--用于分类

  • 什么是embdeding--减少离散变量的空间维数

  • [ ]常见loss及适用任务 比如mse, cross-entropy

  • python list的底层C实现 弄清底层实现原理才能对数据结构设计有更深刻理解,用的时候才不容易出错

  • hook(钩子)使用和原理 一个例子了解hook干啥的 半小时学会pytorch hook

  • shell基本语法资料(完成度50%) 目的:一些需要多个linux指令连续操作的常见就用的上了,比如安装文件,学习了也能看懂别人写的啥,当然觉得也能通过python cmd实现,有机会对比下优劣。 get点:需要用ffmpeg处理9段视频,不会sheel我就只能重复九次CV操作,一点也不优雅。

  • C++基础语法过一遍 目的是能看懂基本代码,比如输入输出,变量声明,速战速决。

  • 非极大值抑制(NMS) c及cuda版本实现, 掌握如何发布C或cuda的python扩展包,提升python工程的运行效率

  • pytorch分布式训练 github 示例 Pytorch DDP分布式训练介绍

  • 多线程与多进程 python使用futures进行并行处理 (发现宝藏博主一枚)

  • 项目源码参考(适合写入简历项目) HumanPose HR-Net 一不小心找到了skl骨骼点源码来源,莫名的熟悉呀,主要看下model.py的区别,看看作了什么优化(这也是主要改动的地方) 思考1:模型这块细节看的比较少,关注结构还是细节呢? 思考2:工程也源于开源,这个项目代码写的还是很不错,所以找到几个不所的开源项目,深入理解整个工程构建逻辑(组织逻辑),比如config、log、command,再就是dataset、train、loss等怎么写的,能学到很多呀。

  • 了解cuda加速原理 官方教材

  • 宝藏书籍收集

    • 《编译原理》了解一行代码背后发生了什么,高级语言->机器语言
    • 《计算机组成原理》至少知道啥是浮点数吧
    • 《数据分析与可视化》张玉宏 知乎上发现的,点通了我对数组axes的理解
  • 宝藏博主收集 纯洁的微笑 python$java教程及应用技术

  • 好的开源项目

  • 整理实习项目

    • 项目背景
    • 遇到的问题、解决思路和方案
    • 承担的角色,做了什么工作
  • 了解下github博客建设 参考一

学习心得

  • 学习pyhton模块时,函数说明看一遍,自己理解记一遍,例程敲一遍
  • 抓主要矛盾,有针对性学习(有目的)学习,就是最近工作项目学习,用到自己还不会的就去学,这个比较高效,但一般由于时间,不会学的很细致,所以一有空就立马补一下,这样相对高效,但也带来一个新问题:学的不够系统,可能是其中几块枝叶,这时需要根求需要去补充,平时见过但用的不多的这种学好点,从来没有见过的过一下,留个印象。所以平时记录自己不会的东西也很重要。
  • 有盼头,也就是有正反馈,正反馈约及时,即所学习的东西越越在短期内带来回报,学习的动力就越大,所以一定要有找到学习的理由,学习这能带给我什么?

每日一学

01.13

01.14

0117

0124

0125-0126

0127

  • 完成新人上路课程(课件,最后一个404)

0209

0210

  • python七大设计模式(今天要过一遍) 目前接触最多就是"单一职责原则",其他的还需要练习

0211

  • 上研院python规范
    • '风格规范'过了一遍(耗时1小时,还得回顾)

0213

  • 复习语言那规范
  • 上研院python规范-常用概念与技巧-迭代器

0214

  • 迭代器与生成器(理解有待加深,yield使用)
  • python3 -m pip install -e . 安装环境(未完成,自己写一个测试下)

0215

  • 上研院python规范过完一边,异常处理、单元测试有待加深学习
  • 常用装饰器
    • @staticmethod(function) 静态方法无需实例化,可以直接调用;不强制要求传递参数
    • @property 方法属性化(不用加()),且不可以修改
    • @classmethod classmethod 修饰符对应的函数不需要实例化,不需要 self 参数,但第一个参数需要是表示自身类的 cls 参数,可以来调用类的属性,类的方法,实例化对象等。用法和@staticmenthod很像,但参数有区别。
  • os.system(cmd) 可以调用系统命令,之前也用过,关键时刻很管用
  • uuid包用来生成唯一标识码
  • config大有讲究,工程的config还是比较复杂 比如config.merge()更新(还未自己实验)

0216

  • shutil 移动文件

0217

  • refile生成的文件列表不是有序的(读取顺序并不一定是目录下顺序) 已经写好的List 读取是肯定有序的, 字典不一定

0222

  • 科学系列(今天至少完成50%)

    • 科学面试(重点) 如何招到公司需要的人
  • 异常处理(常见用法) try...except (try正常执行代码,except处理异常) try...except...else (try执行后再执行else) try...except...finaly(无论如何, finaly都会执行,常用于清理操作) rasie...from... (异常链处理,此处报错源于上一个代码的错误) raise 强制触发的异常(必须是异常实例或异常类(派生自 Exception 类)),如OSError,FileNoFound等

0223

  • 异常处理
分类:分为[1.内置异常](https://docs.python.org/zh-cn/3/library/exceptions.html#bltin-exceptions),这是我们最常见的,2.用户自定义异常,最常用就算文件读取。
**初级心得**:清楚常见异常名称,会异常处理,从而提高代码查错、容错的能力
高级用法:1.异常链:用于处理复杂工程文件报错
  • python3白皮书
    • 第一章 数据结构与算法
      • 1.1、2 将序列,也叫可迭代对象(List, Truple,dict, 字符串等)赋值给变量 特被注意*的使用,在可变长序列赋值时特别有用

0224

  • 第一章 数据结构与算法
    • 1.3 保留最后N个数 可用collections.deque()
    • 1.4 查找最大或最小的N个数 可用heapq下nlargest()和nsmallest()

0228-0318(已经用:18天)

OKR

Object: 对python常用语法掌握更牢靠,数据结构理解更深刻 git使用总结,学会高级操作,常用命令汇总 Key Result: 目标1: - [] 完成python-cookbook(学习1,2,4,5,6,7,8,10,13,14章节内容) (0.8) - [] 跟进和完善学习笔记,争取能拿出手(0.7) 目标2: - [] 会下载commit提交的这版本代码 - [] 会从远端更新本地代码(merge) - [] 出一般详细点学习笔记(给同学能看的)+命令总结(常用的)

  • 第五章 文件与IO

    • open()(很常用)

    • open()读取文本数据(t = 'Hello World')

      • 读取文本:t模式 rt:只读 f.read() wt:可写 f.write()(覆盖原来内容) open('somefile.txt', 'wb')
      • 读取文件默认文本编码方式utf-8,也是最常见的,若读取失败,换格式
      • 读取文本要用with,不用记得手动关闭文件
      • x模式:该文件
    • open()读取字节数据(b = b'Hello World')

      • 读取文本:b模式 rb wb
      • 字节字符串和文本字符串羽翼有差异,若要相互转换需要进行转码:读要解码 写要编码
    • print输出

      • print('内容',file=f)可输出到文本中
      • seq, end 参数改变分割符号和换行符
    • 字符串的I/O操作 可以用来模拟文本或字节文件,特别在测试的时候

      • 使用io.StringIO() 和 io.BytesIO() 类来创建类文件对象操作字符串数据 s = io.BytesIO() s.write(b'binary data') s.getvalue()
      • StringIO 和 BytesIO 实例并没有正确的整数类型的文件描述符(没看太明白)
    • 读写压缩文件

      • 读写一个gzip或bz2格式的压缩文件,使用gzip、bz2模块,操作和内置open()一样
      • 写压缩文件时,可以使用‘compresslevel‘参数制定压缩级别,等级越低性能越好,但是数据压缩程度也越低。
      • 可以作用在一个已存在并以二进制模式打开的文件上(少见)
    • 读取二进制文件到可变缓冲区(无应用场景,不熟)

      • 为了读取数据到一个可变数组中,使用文件对象的 readinto() 方法(必须检查它的返回值)
      • memoryview()可以通过零复制的方式对已存在的缓冲区执行切片操作,还能修改它的内容
    • os.path 文件路径名操作(太常用了,熟记) 来获取文件名,目录名,绝对路径;测试文件夹/文件是否存在;获取文件列表

    • 打印不合法文件名 平时遇到很少,一旦遇到就算令人费解的bug

    • tempfile 创建临时文件/文件夹,默认自动销毁 tempfile.TemporaryFile 创建临时文件,无名字 tempfile.NamedTemporaryFile 创建临时文件,有名字 tempfile.TemporaryDirectory 创建临时文件夹,有名字

    • pickle 序列化python对象--什么是序列化(没遇到过,陌生) 将一个Python对象序列化为一个字节流,以便将它保存到一个文件、存储到数据库或者通过网络传输它。 对于在数据库和存档文件中存储数据时,你最好使用更加标准的数据编码格式如XML,CSV或JSON。

  • 第六章 数据编码与处理(关联性不强,暂定学习)

    • 读写csv数据
      • 普通读取 with open('stocks.csv') as f: f_csv = csv.reader(f) 读取数据 headings = next(f_csv) 索引加一位
      • 使用命名元组 Row = namedtuple('Row', headings)
      • 构建有序字典读取 f_csv = csv.DictReader(f)
      • 数据写入
    • 读写json数据
      • 处理字符串 编码 json.dumps() 解码 json.loads()
      • 处理文件 编码 json.dump() 解码 json.load()
  • 第四章 迭代器与生成器(最常用,必须熟练) 迭代器是Python最强大的功能之一,for item in item: 简单背后是巧妙设计;生成器是创建迭代器的简单而强大的工具。

    • 4.1 手动遍历可迭代对象 如列表、元组、字典、字符串、甚至range(),zip(),enumerate()等函数都能构建可迭代对象(items),而最常用的方式就是“遍历”,常用for语句去遍历,那么实际是如何让操作的呢? 1.用it = iter(items) 构建迭代器 2.用next(it) 运行迭代器,一次迭代一步,直到终止(for 循环中会自动调用 next())
    • 4.2 构造生成器 用yield语句构建一个生成器,生成器只能用于迭代操作 如果需要在一个生成器里调用另一个生成器就需要yield from来帮忙了与yield区别
    • 4.3 反向迭代 可以直接用reversed(),要求对象的大小可预先确定或者对象实现了 reversed() 的特殊方法时才能生效,缺点是消耗内存。 可以重写_reversed__()方法,就算调整输出顺序,这样更高效。
    • 4.4 同时迭代多个序列
      • 用zip(),生成一个可返回元组(x,y,..)的迭代器,长度以短序列为准
      • itertools.zip_longest([迭代对象], fillvalue=0) 长度以长序列为准,不足的补0,默认为None
      • itertools.chain() 接受一个或多个可迭代对象,然后创建一个迭代器,依次连续的返回每个可迭代对象中的元素,相比与a+b,会创建一个新的序列,用chanin()更加高效。
    • 4.5 创建数据处理的pipeline(常用,熟练掌握)
      • 问题:大量的数据需要处理,但是不能将它们一次性放入内存中
      • 重点理解:yield 作为数据的生产者,for循环语句作为数据的消费者;yield from语句,它将 yield 操作代理到父生成器上去。
      • 补充资料:http://www.dabeaz.com/generators/
    • 4.6 展开嵌套的序列 问题:想将一个多层嵌套的序列展开成一个单层列表
      • yield from 语句的递归生成器轻松解决(递归大法好🐶)
      • isinstance(x, Iterable) 还能判断元素是否可迭代,太好用了吧 (from collections import Iterable)
    • 4.7 顺序迭代合并后的迭代对象 问题:有一系列排序序列,想将它们合并后得到一个排序序列并在上面迭代遍历
      • 用heapq.merge(a1, a2, ..) 来解决,它不会立马读取所有序列,所以不会占用太多内存,是多个序列同位置最小值依次输出
      • 序列数据类型需要一致,否则会报错
    • 总结
      • 迭代器是一个更抽象的概念,任何对象,如果它的类有 next 方法和 iter 方法返回自己本身,对于 string、list、dict、tuple 等这类容器对象,使用 for 循环遍历是很方便的。在后台 for 语句对容器对象调用 iter()函数,iter()是python的内置函数。iter()会返回一个定义了 next()方法的迭代器对象,它在容器中逐个访问容器内元素,next()也是 python 的内置函数。在没有后续元素时,next()会抛出一个StopIteration异常。
      • 生成器(Generator)是创建迭代器的简单而强大的工具。它们写起来就像是正规的函数,只是在需要返回数据的时候使用 yield 语句。每次 next()被调用时,生成器会返回它脱离的位置(它记忆语句最后一次执行的位置和所有的数据值)
      • 区别:生成器能做到迭代器能做的所有事,而且因为自动创建了 iter()和 next()方法,生成器显得特别简洁,而且生成器也是高效的,使用生成器表达式取代列表解析可以同时节省内存。除了创建和保存程序状态的自动方法,当发生器终结时,还会自动抛出 StopIteration 异常。
  • 第七章 函数

    • 7.1 接收任意参数的函数

      • 任意位置参数:所有位置参数回放到元组中
         def func(fist, *rest):
            pass
      • 任意关键字参数: 所有关键字参数会放到字典中
        def func(first, **rest):
         pass
      • 两者都有:
        def func(*args, **kwargs):
          print(args)  # A tuple
          print(kwargs) # A dict
    • 7.2 只接收关键字参数(仅支持python3.7+)

      • 强制关键字参数放到某个参数或者单个后面
         def func(*args, rest=None):  
           pass 
         or
         def func(args, *, rest):
            pass
    • 7.3 给函数增加注释(元信息) 目的:增加函数可读性,至少知道输入输出参数分别是啥类型,但解释器不会为此添加任何语义信息,即加不加不影响语法内容。注释信息会保存在函数的__annotations__ 属性里。

      def add(x:int, y:int) -> int:
        return x+y
    • 7.4 定义有默认参数的函数(已经赋值的参数)

      • 定义函数默认后,盗用该函数可以不用给默认参数传参。
      • 默认参数只会定义函数的时候赋值一次,此后不变,除非你再次调用改函数去重新赋值。
      • 默认参数第一次赋值的值应该是不可变的对象,例如:None、True、数字、字符串等,可千万别是:[]这种可对象,可能会在调用过程中改变原有值。
      • 比如长度为0的字符串、列表、元组、字典等)都会被当做False。
    • 7.5 定义匿名函数 问题:函数很短,不想单独写一个函数

      • 实现:func = lambda 参数x:逻辑
      • 与函数不同的是:执行lambda表达式的时候,x的值是执行时的值,当然用默认参数就绑定到值。
      • lambda表达式典型的使用场景是排序或数据reduce
    • 7.6 减少可调用对象参数 使用functools.partial() 模块

      • new_func=partial(func, 参数赋值) 固定某些参数并返回一个新的callable对象
  • 第八章 类与对象(待续,高级用法还是挺难的)

    • 8.1 自定义字符串显示和格式化(用的少,了解)

      • 改变一个实例的字符串表示,可重新定义它的 str() 和 repr() 方法, str() 方法将实例转换为一个字符串,使用 str() 或 print() 函数会输出这个字符串。 repr() 方法返回一个实例的代码表示形式
      • format() 函数和字符串方法使得一个对象能支持自定义的格式化
    • 8.2 让对象支持上下文管理协议(with语句)(用的少,了解) 要实现 enter() 和 exit()方法。当出现with语句的时候,对象的__enter__()方法被触发,它返回的值(如果有的话)会被赋值给as声明的变量。然后,with 语句块里面的代码开始执行。最后,exit() 方法被触发进行清理工作。 这也解释了为啥打开文件要用with open(f) as f: 不用with语句就要手动关闭文件:f.close(),不然容易出现程序崩溃。

    • 8.3 创建大量对象节省内存的方法(用的少,了解)

      • 通过给类添加__slots__属性(包类属性),Python就会为实例使用一种更加紧凑的内部表示。缺点是不能再给实例添加新的属性了,只能使用在 slots 中定义的那些属性名。
    • 8.4 在类中封装属性名(常用,需熟悉) 问题:python没有访问控制,所以通过遵循一定的属性和方法命名规约来达到这个效果(文字性规定,而非语法规定)

      • 以单下划线_开头的名字都应是内部实现,不可外部调用(说归说,你真调用了它也没办法),约定同样适用于模块名和模块级别函数
      • 以双下划线__开头会导致访问名称变成其他形式,这种属性通过继承是无法被覆盖的(就算重名也不会被覆盖,因为解释器会自动改名)
      • 后缀下划线:有时候你定义的一个变量和某个保留关键字冲突,这时候可以使用单下划线作为后缀 如何选用:大多数情况让你的非公共名称以单下划线开头。但是,如果你清楚你的代码会涉及到子类,并且有些内部属性应该在子类中隐藏起来,那么才考虑使用双下划线方案。
    • 8.5 创建可管理属性 问题:方法属性化 用@property修饰对象方法即可,再调用时不需要加(),就像调用一个属性。觉得ndarray.size就是这种用法实现的。

    • 8.6 调用父类方法

      • 直接调用父类的方法:子类方法中super().父类方法
      • 初始化父类方法:super().init()
      • 待补充
    • 8.7 数据结构初始化 构建一个公用的__init__()函数,避免每一个类都重写一个

    • 后面章节就看不懂了

  • 第九章 元编程 就是创建操作源代码(比如修改、生成或包装原来的代码)的函数和类。 主要技术是使用装饰器、类装饰器和元类。

    • 9.1 在函数上添加装饰器 问题:想在不改变原函数情况下,增加额外的操作处理(比如日志、计时等),即对原函数功能进行扩扩充。 理解:一个装饰器就是一个函数,特殊点是:它接受一个函数作为参数,并返回一个新函数(就是对原函数修饰过得到的函数),所以明显标志就是函数结尾:return func,即返回结果是callable。简言之,函数作用于函数。@staticmethod, @classmethod,@property 都是这么来的。

      • 怎么自己写一个装饰器呢? 其实就是写一个正常的函数,用的时候就是@函数名 ,但注意一点需要functools.wrap去修饰一下 了解wraps作用
         def decorate(func):
            @waraps(func)
            # 装饰区:原函数功能扩展
            def wrap(*args, **kwargs):  # 这里的参数就是func参数
               扩展功能逻辑
            return func()
         return decorate                # 返回结果均为可调用对象,可见,有几个def 就有几个return
      • 怎么用,在被修饰对象函数前一行加@decorate
         @decorate
         def func(*args, **kwargs):
            pass
         等价于func = decorate(func)
      • 怎么解除呢?使用func = func.wrapped 即可解除装饰 但并不是所有的装饰器都使用了 @wraps ,因此这里的方案并不全部适用。 特别的,内置的装饰器 @staticmethod 和 @classmethod 就没有遵循这个约定 (它们把原始函数存储在属性 func 中)。
    • 9.2 写一个带参数的装饰器 这个比较常用,比如常用的registy就是这种用法。

      @decorator(x, y, z)
      def func(a, b):
         pass
      等价于def func(a, b):
         pass
      func = decorator(x, y, z)(func)

      延伸:带可选参数的装饰器

      • 就是加入了默认参数以及参数预处理功能即可
    • 9.3 为类和静态方法提供装饰器

      class Spam:
        @timethis
        def instance_method(self, n):
            print(self, n)
        while n > 0:
                n -= 1
      
        @classmethod   # 注意顺序,顺序不可颠倒,否则会报错(简单记:自己写的装饰器在下面)
        @timethis
        def class_method(cls, n):
            print(cls, n)
        while n > 0:
                n -= 1
      
        @staticmethod
        @timethis
        def static_method(n):
            print(n)
            while n > 0:
                n -= 1
      
      
    • 9.4 为函数增加参数(不常用,了解)

      • [疑问]什么是函数签名
    • 9.5 为类扩充功能(不常用,但很有趣,了解) 问题:类功能扩展常用继承:super()来实现,但有趣的是用装饰器也可以且速度更快 实现:类装饰器

    • 9.6 使用元类控制实例创建(不常用,了解) 问题:我想通过改变实例创建方式来实现单例、缓存或其他类似的特性

      • [疑问]什么是元类 后面章节为付费章节(超出目前知识范围),请充值(建议学完以下内容再解锁) 1.元类定义、应用场景、常见用法 2.了解单例、缓存 3.了解参数签名签名用途及用法(相关模块:inspect(相关类:Signature,Parameter))
  • 第十章 模块与包(两天完成)

    • 将代码模块(一个.py文件)封装成包 问题:实现包下各模块快速导入(import),注意不能跨模块导入 实现:实现每个模块同级别目录创建一个__init__文件,一般空着,但其能实现模块自动加载,减少import长度

          # graphics/formats/__init__.py
          from . import jpg
          from . import png

      这样通过import grahpics.formats来代替import graphics.formats.jpg以及import graphics.formats.png。

      • from module import * 语句时, 可以在你的模块中定义一个变量 all 来明确地列出需要导出的内容
    • 文件夹加入到sys.path 问题:一些包无法导入你的Python代码因为它所在的目录不在sys.path,你想将添加新目录到Python路径,但是不想硬链接到你的代码。

      • 第一种,你可以使用PYTHONPATH环境变量来添加, PYTHONPATH=/some/dir:/other/dir python3
      • 第二种方法是创建一个.pth文件,将目录列举出来
    • 安装第三方包 问题:可以把整个工程文件作为一个包安装到系统的site-packages目录中去,可以实现任意路径import 实现:

      • python3 setup.py install --user ,该方法需要写一个setup.py文件(固定格式,看懂就好)
      • pip install --user packagename
    • 分发包 问题:你已经编写了一个有用的库,想将它分享给其他人 实现:编写setup.py,关键包:from distutils.core import setup

      • 步骤一:编写setup.py
           # setup.py
            from distutils.core import setup
            setup(name='projectname',
                version='1.0',
                author='Your Name',
                author_email='you@youraddress.com',
                url='http://www.you.com/projectname',
                packages=['projectname', 'projectname.utils'],
              )
      • 步骤二:创建一个 MANIFEST.in 文件,列出所有在你的包中需要包含进来的非源码文件(没有就不需要了)
          # MANIFEST.in
           include *.txt
           recursive-include examples *
           recursive-include Doc *
           
        最后,确保 setup.py 和 MANIFEST.in 文件放在你的包的最顶级目录中,然后就可以执行安装命令:
        python3 setup.py sdist
        它会创建一个文件比如”projectname-1.0.zip” 或 “projectname-1.0.tar.gz,别人就可以安装使用了
    • 第十四章 测试、调试和异常

      • 10.1 单元测试(目前还没用到过,了解) unittest为常用包,这块先跳过

      • 10.2 处理多个异常(常用,掌握) 简单版:

           try:
              希望执行的内容
           except异常类型1, 异常类型2,···):
              执行不成功的处理措施常用print打印错误信息except (异常类型):
              pass

        这里的"错误类型"都是继承于Exception的异常类,如FileNotFoundError,OSError等,异常类才可以被except识别,except语句是顺序检查的 错误类型名字习惯:错误类型+Error 所以得了解常见的异常类,才好作针对性处理,对于Debug也很有好处。 小提示:可用__mro__查看类的继承关系,如print(FileNotFoundError.mro) 升级版:

          try:
             f = open(filename)
          except OSError as e:
             if e.errno == errno.ENOENT:
                logger.error('File not found')
             elif e.errno == errno.EACCES:
                logger.error('Permission denied')
             else:
                logger.error('Unexpected error: %d', e.errno)

        这个例子中,e变量指向一个被抛出的OSError异常实例。这个在你想更进一步分析这个异常的时候会很有用,比如基于某个状态码来处理它。

      • 10.3 捕获所有异常(常用,掌握) 问题:捕获所有异常通常是由于程序员在某些复杂操作中并不能记住所有可能的异常。这个无法针对特定错误作处理,但可以告诉我们有发生什么错误了,比啥也不知道好吧。 实现:可以直接捕获 Exception 即可,

           try:
              pass
           except Exception as e:  
               print('reason', e)  # 

        这个将会捕获除了SystemExit、KeyboardInterrupt和GeneratorExit之外的所有异常。如果你还想捕获这三个异常,将Exception 改成 BaseException(这是最顶层的基类了) 即可。

      • 10.4 创建自己的异常(用的少,了解) 问题:将底层异常包装成自定义的异常,也说明底层异常是固定的,我们只能进行组合包装。 实现:创建新的异常——定义新的类,让它继承自Exception或者任何一个已存在的异常类型。但很不建议继承与BaseException,因为BaseException是为系统退出异常而保留的,比如KeyboardInterrupt或SystemExit以及其他那些会给应用发送信号而退出的异常,捕获这些异常本身没什么意义。

      • 10.5 捕获异常后抛出另外的异常(常见,熟悉) 问题:想捕获一个异常后抛出另外一个不同的异常,同时还得在异常回溯中保留两个异常的信息。 实现:使用raise from语句来代替简单的raise语句

           def example():
               try:
                  int('N/A')
               except ValueError as e:
                   raise RuntimeError('a parsing error occured') from e

        这样ValueError和RuntimeError就构成了一个异常链,前者是造成后者的直接原因。 使用rasise from None 可忽略掉异常链(忽略ValueError)

           try:
              example()
           except RuntimeError as e:
               print('it didnt work:', e)
               if e.__cause__:
                  print('Cause:', e.__cause__)

      但当在 except 块中又有另外的异常被抛出时会导致一个隐藏的异常链的出现,此时可以用异常对象的 cause 属性来跟踪异常。

      • 10.6 重新捕获被抛出的异常(常用,掌握) 问题:在except块中捕获了一个异常,现在想重新抛出:当你需要在捕获异常后执行某个操作(比如记录日志、清理等),但是之后想将异常传播下去 实现:单独使用 raise 语句即可

           try:
             int('N/A')
           except ValueError:
              print('didnt work')
          raise
      • 10.7 输出警告信息(常见,掌握) 问题:希望自己程序能够自己生成警告信息(比如废弃特性或使用问题)

        • 在你维护软件,提示用户某些信息,但是又不需要将其上升为异常级别,那么输出警告信息就会很有用了。

        • 使用新版库时经常会有警告信息,但仍然能用(开发者准备修改某个函数库或框架的功能,可以先为要更改的部分输出警告信息,同时向后兼容一段时间。 还可以警告用户一些对代码有问题的使用方式。) 实现:使用 warning.warn() 函数实现

        • warn() 的参数是一个警告消息和一个警告类(和异常类很类似),警告类有如下几种:UserWarning, DeprecationWarning, SyntaxWarning, RuntimeWarning, ResourceWarning, 或 FutureWarning.

           import warning
           def (x, y, logfile=None):
             if logfile is not None:
                    warning.warn('logfile argument deprecated', DeprecationWaring)
        • 对警告的处理取决于你如何运行解释器以及一些其他配置:-W 选项能控制警告消息的输出

          • *python -W all .py 会输出所有警告消息
          • -W ignore 忽略掉所有警告
      • -W error 警告转异常

      • 10.8 调试崩溃的程序(debug)(非常常用,熟练)

        • 最简单的:print()定位bug,解决后删除(我最常用的)
    • IDE调试器(用的太少,需要补补)

      • 10.9 程序性能测试及加速(常见,了解) 代码加速常用:平时写代码多注意
        • 尽可能去掉属性访问 少用.导入包,会触发特定的方法,比如 getattribute() 和 getattr() ,这些方法会进行字典操作操作
        • 局部变量会比全局变量运行速度快
        • 避免不必要的抽象 使用额外的处理层(比如装饰器、属性访问、描述器)去包装你的代码时,都会让程序运行变慢
        • 使用内置的容器 内置的数据类型比如字符串、元组、列表、集合和字典都是使用C来实现的,运行起来非常快。 如果你想自己实现新的数据结构(比如链接列表、平衡树等), 那么要想在性能上达到内置的速度几乎不可能。
        • 避免创建不必要的数据结构或复制

0320 numpy学习 (用时11天)

OKR

Object

  • 学会数组常见处理

Key Result

  • 学习完菜鸟教程

  • 数位操作 1.修改数组形状(常用,熟悉)

    函数 描述
    reshape 改变成任意形状(不改变变数据的条件下)
    flatten 展开数组(返回一份拷贝的数组,对其该改变不会影响原来数组,默认按行‘C’展开)
    ravel 展开数组(改变会影响原数组)
  1. 翻转数组(见到过,掌握)
  • numpy.transpose(arr, axes) 对换数组维度 参数说明:
    • arr:要操作的数组, axes:对应维度, 默认所有维度都换
  • numpy.ndarray.T 转置数组,等价于numpy.transpose
  • numpy.rollaxis(arr, axis,start) (没整明白) 向后滚动特定的轴到一个特定位置 参数说明:
    • axis:要向后滚动的轴,其它轴的相对位置不会改变
    • start:默认为0, 表示完整滚动,会滚到特定位置
  • numpy.swapaxes(arr, axis1, axis2) 用于交换数组的两个轴 参数说明:
    • axis1:对应的第一个轴
    • axis2:对应的第二个轴 3.修改数组维度 - np.broadcast(arr1, arr2) 用于模仿广播的对象,返回一个可迭代对象,该对象封装了一个数组广播到另一个数组的集结果(但不能直接打印出来,需要用迭代方法iter,用next一个个取出来) 参数说明:两个数组,低纬模仿高维 - np.broadcast_to(array, shape, subok) 将数组广播到新形状,如果新形状不符合 NumPy 的广播规则,该函数可能会抛出ValueError. 广播规则:数组最小单位要一致,比如原数组形状为(3,),那么广播后的形状必须形如(-,-,3)这样。 数组的理解:就是一组数量有限的数值,按照约定的格子排列。仅从数字角度看,这并没有什么含义,怎么排都可以,又不会改变数据,但当有了实际场景需求,这种排列便有了含义,比如图像数据,按照(C,W,H)方式排列,C表示图像RGB三通道,W和H表示每个通道图像像素的宽度,CHW这些只是约定格子的排列方式(即数组的形状), 并不能实际表示数据,也不会改变数据,它们的作用就是画好了格子,数据放进去便有了实际物理意义。 - np.expand_dims(arr, axis) 在指定位置插入新轴来扩展数组形状,在图片传入network常需要扩维(四维),以满足网络对尺度的要求 理解:随便插入一个轴,确实容易绕糊涂,但我们只要转换后的形状,根据最小单元原则即可推出转后的数组。 - np.squeeze(arr, axis) 删除数组的维度为1的那一个轴,axis默认为0 扩展数组维度:np.unsqueeze(arr, axis)

3.连接数组 - np.concatenate((arr1, arr2, ..), axis=0) 用于沿着某指定轴连接形状相同的数组,注意这个轴是有arr决定的,故生成的数组轴数量不会变化 比如两个(2,2)数组沿着0轴连接,连接数组维度为(4,2) - np.stack(arrays, axis) 用于沿新轴连接数组序列,与上面的区别是:轴的数量会加1 参数说明:arrays相同形状的数组序列 - np.hstack((arr1,arr2)) 是np.stack()函数的变体,通过水平堆叠来生成数组(相当于在axis=0进行stack()) - np.vstack((arr1, arr2))

4.分割数组

  • np.split(arr, indices_or_sections, axis=0) 沿着特定的轴将数组分割为子数组 参数说明:

    • indices_or_sections:如果是一个整数,就用该数平均切分,如果是一个数组,为沿轴切分的位置(左开右闭)(简单说就是分割的间隔)
    • axis 为 0 时在水平方向分割,axis 为 1 时在垂直方向分割(不能超出数组的轴数)
  • np.hsplit(arr, indices_or_sections) 水平轴分割数组(对二维数组,可以看成竖着切一刀)

  • np.vsplit(arr, indices_or_sections) 垂直轴分割数组(对二维数组,可以看做横着切一刀) 问题:对于二维数组有水平轴,垂直轴一说(相当于axis=0, 1),但对于二维以上还有这种说法吗? 思考:确实只有二维数组才有水平轴和垂直轴一说(人为规定,为了好可视化,也便于理解),但根据最小单元原则,任何高于2维的数组,比如三维数组(n ,4 , 4),都可以分解为n个二维数组,这时候又可以这么叫了,对于四维数组(m, n, 4, 4),能分解为m个三维数组,每一个三维数组又可以分解为n个二维数组,不又可以这么叫了。对于CNN,所用数据基本都在二维以上,如果以都以这种方式去强行可视化,对于高维数据还是很吃力,所以我们需要一种通用的方式去重新看待数组的维度:参考

5.数组元素的添加与删除 - np.resize(arr, shape) 返回指定大小的新数组,与reshape区别是,这里shaped形状乘积可以不等于原来数组的个数,也就是说不够会自动复制原数组,直到满足重新设置的新形状。 - np.append(arr, values, axis=None) 在数组的末尾添加值。 追加操作会分配整个数组,并把原来的数组复制到新数组中,输入数组的维度必须匹配否则将生成ValueError. 参数说明: - arr:输入数组 - values:向arr添加的值,需要和arr形状相同(除了要添加的轴) - axis:默认为None,此时是横向添加,返回总是一维数组。当axis有定义时候(行数必须相同),当axis=1时,数组是加在右边(行数要相同)。 - np.insert(arr, obj, values, axis) 在给定索引之前,沿给定轴在输入数组中插入值。如果值的类型转换为要插入,则它与输入数组不同。 插入没有原地的,函数会返回一个新数组。 此外,如果未提供轴,则输入数组会被展开。(没理解) 参数说明: - arr:输入的数组 - obj:在其之前插入值的索引 - values:要插入的值 - axis:沿着它插入的轴,如果未提供,则输入数组会别展开

- np.delete(arr, obj, axis)
  从输入数组中删除指定子数组的新数组。 与 insert() 函数的情况一样,如果未提供轴参数,则输入数组将展开。
  参数说明:
   - obj:可以被切片,整数或者整数数组,表明要从输入数组删除的子数组
- np.unique(arr, return_index, return_inverse, return_counts)
  用于去除数组中重复的元素
  参数说明:
   - arr:输入数组,如果不是一维会自动展开(变为以一维)
   - return_index:若为true,返回列表元素在旧列表的中的位置下标,以列表形式存储
 - return_inverse:若为true, 返回列表在新列表中未在
   - return_counts: 返回去重数组中的元素在原数组中的出现次数
  • 数学函数

    • np.floor(arr) 返回小于或者等于指定表达式的最大整数(按位向下取整)
    • np.ceil(arr) 返回大于或者等于指定表达式的最小整数(按位向上取整数)
  • 算术运算

    • np.reciprocal(arr) 按位求倒数
    • np.power(arr1, arr2) 将第一个输入数组中的元素作为底数,计算它与第二个输入数组中相应元素的幂(也可以就是一个整数)
    • np.mod(arr1, arr2) 计算输入数组中相应元素的相除后的余数。 函数 numpy.remainder() 也产生相同的结果。
  • 统计函数

    • np.amin(arr, axis=None) 用于计算数组中的元素沿指定轴的最小值, 不指定就求全局最小值
    • np.amax(arr, axis=None) 用于计算数组中的元素沿指定轴的最大值。
    • np.ptp(arr, axis=None) 用于计算数组中元素最大值与最小值的差值
    • np.median(arr, axis=None) 用于计算数组 a 中元素的中位数(中值)
    • np.mean(arr, axis=None) 返回数组中元素的算术平均值。 如果提供了轴,则沿其计算。(算术平均值是沿轴的元素的总和除以元素的数量)
    • np.average(arr, weights) 根据在另一个数组中给出的各自的权重计算数组中元素的加权平均值.该函数可以接受一个轴参数。 如果没有指定轴,则数组会被展开.加权平均值即将各数值乘以相应的权数,然后加总求和得到总体值,再除以总的单位数
    • np.std(arr) 求标准差,标准差是一组数据平均值分散程度的一种度量。标准差是方差的算术平方根
    • np.var(arr) 求方差
  • 排序和筛选

    • np.sort(a, axis, kind, order) 返回输入数组排序后副本 参数说明:
      • axis:沿着它排序数组的轴,如果没有数组会被展开,沿着最后的轴排序
      • kind: 默认为'quicksort'(快速排序),还有mergesort、heapsort(堆排序),速度依次降低,稳定性依次提高。
      • order: 如果数组包含字段,则是要排序的字段(没咋懂)
    • np.argsort() 是数组值从小到大的索引值
    • np.argmin() np.argmax() 沿给定轴返回最大和最小元素的索引
    • np.nonzero() 返回输入数组中非零元素的索引
    • np.where() 返回输入数组中满足给定条件的元素的索引
    • np.extract(condition, arr) 根据某个条件从数组中抽取元素,返回满条件的元素(一维的)

0331 了解浮点数及其量化原理 (未完成)

IEEE 754浮点数 没咋看懂,可能基础不够 知识来源-《计算机组成原理》

0401 @click

当我们构建好工程,功能比较完善的时候,可以快速快捷执行代码,比如像MMDectection

  • 学习@click 快速构建命令行 确实比Argparse好用不少

0409 os库

主要用来处理文件/目录 下面主要总结下非常常用的m

  • os.path 模块主要用于获取文件的属性(以下简写op)
    • op.abspath(path) 返回绝对路径
    • op.basename(path) 返回文件名
    • op.dirname(path) 返回该文件的目录路径
    • op.exists(path) 如果路径存在,返回True;反之,返回False
    • op.isfile(path) 判断路径是否为文件
    • op.isdir(path) 判断路径是否为目录
    • op.join(path, filename1) 把目录和文件合成一个路径
    • op.split(path) 把路径分割成dirname和basename, 返回一个元组
    • op.getsize(path) 输出文件大小(字节为单位)
  • os.listdir(path) 指定路径下的文件和文件夹列表 如果目录名字为中文 需要转码处理
     Path = unicode(Path,'utf-8')
     list = os.lisdir(Path)
  • os.open(file, flags) 打开一个文件fd(创建了一个对象) 文件先open,再读写 参数说明:flags
    • os.O_RDONLY: 以只读的方式打开
    • os.O_WRONLY: 以只写的方式打开
    • os.O_RDWR : 以读写的方式打开
    • os.O_CREAT: 创建并打开一个新文件
  • os.write(fd, "str") 写入字符串
  • os.read(fd, n) 从文件描述符 fd 中读取最多 n 个字节,返回包含读取字节的字符串,文件描述符 fd对应文件已达到结尾, 返回一个空字符串。
  • os.close(fd) 关闭文件
  • os.getcwd(path) 返回当前工作目录
  • os.mkdir(path) 创建一个名为path的文件夹
  • os.remove(path) 删除路径为path的文件,如果path是文件夹,会报OSError
  • os.removedirs(path) 递归删除目录(该目录下所有目录)

该模块提供了一些接口,用于访问 Python 解释器自身使用和维护的变量

  • sys.argv 是一个列表对象,其中存储的是在命令行调用 Python 脚本时提供的“命令行参数”。 第一个参数就是脚本名称,后面就是输入的参数了,这个和command()有点类似,但没法对输入参数进行约束,所以还不够好用。

  • sys.modules 该属性是一个字典,包含的是各种已加载的模块的模块名到模块具体位置的映射

  • sys.path 该属性是一个由字符串组成的列表,其中各个元素表示的是 Python搜索模块的路径;在程序启动期间被初始化。其中第一个元素(也就是path[0])的值是最初调用 Python 解释器的脚本所在的绝对路径

    • sys.path.append("自定义模块路径")
  • sys.exit([arg]) 执行到主程序末尾,解释器自动退出,但是如果需要中途退出程序,可以调用sys.exit函数。可选参数 arg 可以是表示退出状态的整数(默认为 0),也可以是其他类型的对象。如果它是整数,则 shell 等将 0 视为“成功终止”,非零值视为“异常终止”。

  • sys.stdin python的标准输入

  • sys.stdout python的标准输出 通过将这个属性的值修改为某个文件对象,可以将本来要打印到屏幕上的内容写入文件,可以生成临时日志文件

0410 pathlib

面向对象的的文件系统路径,常用 from pathlib import Path

0410 logging

官方文档 实现灵活的事件日志记录的函数和类,以下这张图反应了我们应该根据任务去选择适合的记录工具。 日志级别等级排序:critical > error > warning > info > debug,级别越高打印的日志越少,反之亦然. 使用方式:

  • 方式一:使用 Logging 提供的模块级别的函数(手动版) 程序比较简单适用 先用logging.basicConfig()配置日志,再用logging.info('内容')记录日志(注意如果是多程序的哈话,需配置需要写在主文件里,子文件用.info('信息')写入就行。)
  • 方式二:使用Logging 日志系统的四大组件记录 更为灵活,训练日志常用方式 组成:日志器(logger)是入口,真正干活儿的是处理器(handler),处理器(handler)还可以通过过滤器(filter)和格式器(formatter)对要输出的日志内容做过滤和格式化等处理操作。Logger 可以包含一个或多个 Handler 和 Filter. 使用方式:
    • 创建一个logger:负责初始化及log文件的创建(最好专门写一个函数,方便复用)
         head = '%(asctime)-15s %(message)s' # 设置输出日期时间格式
         logging.basicConfig(filename=file_path,format=head) # filename log保存路径
         # 创建logger
         logger = logging.getLogger()  
         logger.setLevel(logging.INFO) # 设置信息级别
         # 创建handler
         console = logging.StreamHandler()
         logging.getLogger('').addHandler(console) # logger加入处理器
    • 写入信息
      logger.info('信息')
      这里涉及到多个程序如何写入到同一个日志,这里需要使用logger = logging.getLogger(name)(默认__name__),名字相同即同一个logger

0412 torch.dataloader中的多进程

参考资料:

torch加载数据有两个关键类:DataSet和DataLoader, 前者是一个迭代器,负责把数据集(标签和图片数据)转为一个可迭代对象,给一个索引返回一个样本,且负责图片的预处理(必须的是转tensor,可选的是各种数据增强),以及标签的编码(比如骨骼点转为热力图)。接下来就是dataloader登场了,它负责每次加载多少数据送入GPU进行训练,所以本质也是一个可迭代的对象(此时模型已经再GPU里等待数据了),所以这里是影响训练速度的关键。

快速看用法 功能上实现了特定目标的容器,以提供Python标准内建容器 dict , list , set , 和 tuple 的替代选择(即继承原有容器,进行功能升级) 以下根据常用子模块的进行排序:

  • OrderedDict() (字典的子类,保存了他们被添加的顺序) 使用dict时,Key是无序的。在对dict做迭代时,我们无法确定Key的顺序, 用:

      d = OrderedDict()
      d = {'a':2, 'b':2}
    
  • defaultdict(default_factory) 字典的子类,提供了一个工厂函数,为字典查询提供一个默认值 解决字典中key值不存在抛出KeyError的错误。default_factory应该是一个函数,当没有参数调用时返回默认值,比如可以是int,key值不存在返回0.(注:用dict.get(key)类似,不存在返回None)

  • deque 类似列表(list)的容器 实现了在两端快速添加(append)和弹出(pop),使用和List类似。

  • Counter 字典子类,用来对你访问的对象的频率进行计数

  • namedtuple() 元组子类, 继承了元组所有的的特性 特别之处在于你可以通过名字来访问元组中的元素,类似字典,通过key来访问value。

  • ChainMap() 将多个字典或者其他映射组合在一起

目的是理解torch dataloader用到的多线程

0417 python扩展包 (待完成:无一假期完成)

了解python 扩展包的构建过程,需要什么文件,配置什么文件,得到什么文件,怎么用这些文件,会用是第一目标。 python cookbook C扩展 Python 非极大值抑制(NMS)的四种实现详解 Distutils发布c++扩展的python模块setup.py CUDA和C++混合编译实现Python扩展

  • 实战一:构建NMS C++版的python扩展包 参考项目1-skl 目的:

    • 1.了解Cpython干啥的
    • 2.setup.py 中这块怎么写的,顺带了解Makefile文件干啥的
    • 3.nms原理,py实现,C++实现
  • 实战二:构建NMS CUDA版的python扩展包 目的:

    • 1.setup.py这块怎么写的
      1. cuda简单语法,怎么实现的NMS

0428 hook原理和实现

hook 并不是一种语法而是一种设计模式,从功能上看和装饰器基本差不多(具体区别还在对比中) 它的实现由三部分构成:

  • 1.hook函数:用于实现自己的目的
  • 2.挂载:将hook函数注册到目标位置,这样目标位置才能用上它
  • 3.目标挂载点:也就是目标函数位置

五一假期计划(5.1-5.5)

任务优先级:

  • C++基础语法过一遍 (4.30) 目标:了解数据结构、基本语法、能看懂leetcode上c++代码

  • [ ]python扩展包(NMS c++ cuda编译 ) (详情见4.17日志)(5.1)

    • 实战一:构建NMS C++版的python扩展包 参考项目1-skl 目的:

    • 1.了解Cpython干啥的

    • 2.setup.py 中这块怎么写的,顺带了解Makefile文件干啥的

    • 3.nms原理,py实现,C++实现

    • 实战二:构建NMS CUDA版的python扩展包 目的:

    • 1.setup.py这块怎么写的

      1. cuda简单语法,怎么实现的NMS
  • python并发编程及分布式训练 1.再理解线程和进程 2.再梳理dataloader实现 3.再梳理dataparral 与distdataparal实现逻辑 4.自己实现一个分布式训练

  • [ ]整理实现项目与简历

  • [ ]剪辑视频

    • 中山公园视频内容制作:抖音版&b站版
    • 了解抖音推荐原理,分析拉流因素,指定制作方向