手撕Pytorch源码#4.Dataset类 part4

news2024/11/15 11:20:20

写在前面

  1. 手撕Pytorch源码系列目的:

  • 通过手撕源码复习+了解高级python语法

  • 熟悉对pytorch框架的掌握

  • 在每一类完成源码分析后,会与常规深度学习训练脚本进行对照

  • 本系列预计先手撕python层源码,再进一步手撕c源码

  1. 版本信息

python:3.6.13

pytorch:1.10.2

  1. 本博文涉及python语法点

  • json库的使用

  • pickle库的使用

  • __reduce__方法与__reduce_ex__方法

  • *args与**kwargs

  • @classmethod

目录

[TOC]

零、流程图

一、填坑python高级语法点

1.1 Json库的使用
1.1.1 Json的数据类型与Python数据类型

Python

Json

dict

object

list,tuple

array

str

string

int,float,...

number

True

true

False

false

None

null

  • Json对象都是小写的,而Python的True,False,None都是大写开头的,注意区分

  • Python字典对象中所有键值都是单引号格式的,而Json对象中所有键值都是双引号格式的

pydict = {
    "Pytorch":"1.10.2",
    "Python":"3.6.13",
    "Other_lib":["numpy","pandas","matplotlib",'sklearn']
}
pyjson = json.dumps(pydict,indent=4,sort_keys=True)
print("pydict: {}".format(pydict))
print("pyjson: {}".format(pyjson))

# 输出结果为:
# pydict: {'Pytorch': '1.10.2', 'Python': '3.6.13', 'Other_lib': ['numpy', 'pandas', 'matplotlib', 'sklearn']}
# pyjson: {
#     "Other_lib": [
#         "numpy",
#         "pandas",
#         "matplotlib",
#         "sklearn"
#     ],
#     "Python": "3.6.13",
#     "Pytorch": "1.10.2"
# }
1.1.2 dump和load操作
  • json.dumps是将python对象转化成json字符串对象

pydict = {
    "Pytorch":"1.10.2",
    "Python":"3.6.13",
    "Other_lib":["numpy","pandas","matplotlib",'sklearn']
}
# indent = 4是为了让显示出的格式更好看
# sort_keys = True为了给Key排序
pyjson = json.dumps(pydict,indent=4,sort_keys=True)
print("pydict: {}".format(pydict))
print("pyjson: {}".format(pyjson))
print("type of pydict is {}".format(type(pydict)))
print("tyoe of pyjson is {}".format(type(pyjson)))

# 输出结果为:
# pydict: {'Pytorch': '1.10.2', 'Python': '3.6.13', 'Other_lib': ['numpy', 'pandas', 'matplotlib', 'sklearn']}
# pyjson: {
#     "Other_lib": [
#         "numpy",
#         "pandas",
#         "matplotlib",
#         "sklearn"
#     ],
#     "Python": "3.6.13",
#     "Pytorch": "1.10.2"
# }
# type of pydict is <class 'dict'>
# tyoe of pyjson is <class 'str'>
  • json.dump将python对象转化成json文件

with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\data.json","w") as f:
    json.dump(pydict,indent=4,fp=f)
    f.close()
{
    "Pytorch": "1.10.2",
    "Python": "3.6.13",
    "Other_lib": [
        "numpy",
        "pandas",
        "matplotlib",
        "sklearn"
    ]
}
  • json.loads将json字符串对象转化成python对象

pyobj = json.loads(pyjson)
print("pyobj:{}".format(pyobj))
print("type of pyonj is {}".format(type(pyobj)))
# 输出结果为:
# pyobj:{'Other_lib': ['numpy', 'pandas', 'matplotlib', 'sklearn'], 'Python': '3.6.13', 'Pytorch': '1.10.2'}    
# type of pyonj is <class 'dict'>

jsonstr = '["1","2",{"Version":"1.10.2","download":true}]'
pyobj_ = json.loads(jsonstr)
print("pyobj_:{}".format(pyobj_))
print("type of pyonj_ is {}".format(type(pyobj_)))
# 输出结果为:
# pyobj_:['1', '2', {'Version': '1.10.2', 'download': True}]
# type of pyonj_ is <class 'list'>
  • json.load将json文件解码为python对象

with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\data.json","r") as f:
    pyobj_file = json.load(fp=f)
    f.close()

print("pyobj_file:{}".format(pyobj_file))
print("type of pyonj_file is {}".format(type(pyobj_file)))
# 输出结果为:
# pyobj_file:{'Pytorch': '1.10.2', 'Python': '3.6.13', 'Other_lib': ['numpy', 'pandas', 'matplotlib', 'sklearn']}
# type of pyonj_file is <class 'dict'>
1.1.3 Encoder编码器
  • json库的默认编码器encoder不能编码自定义的类型,代码如下:

class Lib():
    def __init__(self,data:str) -> None:
        self.data = data

    def __repr__(self) -> str:
        return str(self.data)

pydict = {"name":Lib("Pytorch"),"version":"1.10.2"}
json.dumps(pydict,indent=4)
# 代码报错如下:
# TypeError: Object of type Lib is not JSON serializable
  • 需要自己定义解码方式,需要继承json.JSONEncoder类,并且重载default方法,代码如下:

class Lib():
    def __init__(self,data:str) -> None:
        self.data = data

    def __repr__(self) -> str:
        return str(self.data)

pydict = {"name":Lib("Pytorch"),"version":"1.10.2"}

class Jsonencode(json.JSONEncoder):
    def default(self, o: typing.Any) -> typing.Any:
        if isinstance(o,Lib):
            # 相当于调用了__repr__方法
            return str(o)
        return super(self).default(o)

pyjson_encode = json.dumps(pydict,cls = Jsonencode,indent=4)
print("pyjson_encode:{}".format(pyjson_encode))
# 输出结果为:
# pyjson_encode:{
#     "name": "Pytorch",
#     "version": "1.10.2"
# }
1.1.4 object_hook自定义方式解码(Specializing JSON object decoding)
  • 在使用json.load函数时,可以自定义解码方式,示例代码如下:

# 用object_hook解码(Specializing JSON object decoding)
def as_complex(dct:typing.Dict)->typing.Union[typing.Dict,complex]:
    if "__complex__" in dct:
        return complex(dct["real"],dct["imag"])
    return dct

pyobj_decode = json.loads('{"__complex__":true,"real":2,"imag":1}',object_hook=as_complex)
print("pyobj_decode:{}".format(pyobj_decode))
# 输出结果为:
# pyobj_decode:(2+1j)
1.2 pickle库
1.2.1 pickle库的使用
  • pickle库和json库的作用类似,都是对数据进行序列化和反序列化的操作,但是由于json与编程语言无关,因此对python数据的支持较弱,而pickle库则对python各种数据类型有较强的支持性

  • json文件是可读性较强的字符串格式,而pickle则是可读性较弱的二进制格式,因此在使用open()函数时,写入和读取的模型应该分别为:wb和rb

  • pickle数据类型与json数据类型的相互编码解码同样由四个函数完成pickle.dumps(),pickle.dump(),pickle.loads(),pickle.load()

  • 上述四个函数的使用如下:

import pickle

# pickle.dumps()
class Lib():
    def __init__(self,name) -> None:
        self.name = name

pydict = {'name':Lib("Pytorch"),"version":"1.10.2"}
pypickle = pickle.dumps(pydict)
print(f"pypickle : {pypickle}")
print(f"type of pypickle : {type(pypickle)}")
# 输出结果为:
# pypickle : b'\x80\x04\x95E\x00\x00\x00\x00\x00\x00\x00}\x94(\x8c\x04name\x94\x8c\x08__main__\x94\x8c\x03Lib\x94\x93\x94)\x81\x94}\x94h\x01\x8c\x07Pytorch\x94sb\x8c\x07version\x94\x8c\x061.10.2\x94u.'
# type of pypickle : <class 'bytes'>

# pickle.dump()
with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\data.pickle","wb") as f:
    pickle.dump(pydict,f)
    f.close()

# pickle.loads()
pydict_ = pickle.loads(pypickle)
print(f"pydict_ : {pydict_}")
print(f"type of pydict_ : {type(pydict_)}")
# 输出结果为:
# pydict_ : {'name': <__main__.Lib object at 0x0000022C97E65F70>, 'version': '1.10.2'}
# type of pydict_ : <class 'dict'>

# pickle.load()
with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\data.pickle","rb") as f:
    pydict_ = pickle.load(f)
    f.close()
print(f"pydict_ : {pydict_}")
print(f"type of pydict_ : {type(pydict_)}")
# 输出结果为:
# pydict_ : {'name': <__main__.Lib object at 0x0000022C97E65F10>, 'version': '1.10.2'}
# type of pydict_ : <class 'dict'>
  • 由上述代码可以发现,pickle库可以直接支持python自定义的数据类型,而不需要配置encoder【配置encoder定义一个类,继承json.JSONEncoder类,重载default方法】

1.2.2 pickle库的危险性
  • 不要轻易反序列化不可信任的pickle文件!

  • 简单的构造具有危险性的代码

import pickle
import typing
import os


class Dangerous:
    def __init__(self) -> None:
        pass
    # 专门为pickle预留的魔法方法,允许用于定义较为复杂的复原object的方式
    def __reduce__(self) -> str or tuple[typing.Any, ...]:
        return (
            os.system,
            ("dir",),
        )

danger = Dangerous()
with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\dangerous","wb") as f:
    pickle.dump(danger,f)
    f.close()

with open(".\\Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention\\手撕Pytroch第四期\\dangerous","rb") as f:
    pickle.load(f)
    f.close()

# 输出结果为:
# 2023-01-23  01:25    <DIR>          .
# 2023-01-23  01:25    <DIR>          ..
# 2023-01-23  12:26    <DIR>          Deep-Learning-Image-Classification-Models-Based-CNN-or-Attention
# 2023-01-11  23:26                96 GitHub克隆地址.txt
#                1 个文件             96 字节
#                3 个目录 65,380,278,272 可用字节
  • 上述代码中的__reduce__函数相当于让pickle.load打开了一个windows终端,并输入dir命令

  • 当程序可以直接操作终端,相当于防线被攻破,有极大的风险

1.3 __reduce__和__reduce_ex__函数
  • __reduce__和__reduce_ex__都是为了pickle库专门创建的魔法方法,用于定义较为复杂的复原object的方式

  • 具体用法见上1.2.2中的代码

  • IterableDataset中的函数正是此目的:

    def __reduce_ex__(self, *args, **kwargs):
        if IterableDataset.reduce_ex_hook is not None:
            try:
                return IterableDataset.reduce_ex_hook(self)
            except NotImplementedError:
                pass
        return super().__reduce_ex__(*args, **kwargs)
1.4 *args与**kwargs
  • *args是位置参数,必须按照顺序传入,**kwargs是关键字参数,按照关键字名称传入,可以不按顺序。且关键字参数keyword argument必须在位置参数argument之后

  • *和**其实是解包符号,类似电脑中的解压软件

  • 其中*解元组的包,因而对应位置参数

  • **解字典的包,因而对应关键字参数

1.4.1 利用*args或**kwargs捕捉传入的值
  • 可以直接使用for loop遍历args以及kwargs,代码如下:

def try_args(arg1,*args)->None:
    print("arg1 = {}".format(arg1))
    for arg in args:
        print("Optional Argument = {}".format(arg))

try_args(1,2,3,4)
# 输出结果1:
# arg1 = 1
# Optional Argument = 2
# Optional Argument = 3
# Optional Argument = 4

def try_kwargs(arg1,**kwargs)->None:
    print("arg1 = {}".format(arg1))
    for key,arg in kwargs.items():
        print("Optional Argument key {} : {}".format(key,arg))

try_kwargs(1,arg2=2,arg3 =3,arg4 = 4)
# 输出结果2:
# arg1 = 1
# Optional Argument key arg2 : 2
# Optional Argument key arg3 : 3
# Optional Argument key arg4 : 4
1.4.2 直接以元组(字典)方式传入参数
  • 由上文可知,*是元组的解包符号,**是字典的解包符号,因而可以对应传入元组或字典,并且利用对应的解包符号进行解包传值,代码如下:

def try_args_kwargs(arg1,arg2,arg3)->None:
    print("arg1:{}".format(arg1))
    print("arg2:{}".format(arg2))
    print("arg3:{}".format(arg3))

args = (1,2,3)
kwargs = {'arg1':1,'arg2':2,'arg3':3}

try_args_kwargs(*args)
# 输出结果1:
# arg1:1
# arg2:2
# arg3:3

try_args_kwargs(**kwargs)
# 输出结果2:
# arg1:1
# arg2:2
# arg3:3
1.5 @classmethod
  • @classmethod修饰器声明了一个属于类的方法,在调用的时候可以直接通过类名进行调用,或者通过对象进行调用

  • @classmethod有什么意义呢?他可以让继承的子类不需要重载父类的初始化函数,而只需要定义一个属于类的方法即可,直接上代码:

class Time():
    def __init__(self,hour:int,minute:int)->None:
        self.hour = hour
        self.minute = minute

class String_Time(Time):
    @classmethod
    def get_version(cls,time:str)->Time:
        hour,minute = map(int,time.split(":"))
        Time_1 = Time(hour,minute)
        return Time_1

time = String_Time.get_version("12:34")
print(time.hour)
print(time.minute)

# 输出结果为:
# 12
# 34

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/176665.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据之HBase集群搭建

文章目录前言一、上传并解压HBase安装包二、修改HBase配置文件&#xff08;一&#xff09;hbase-env.sh&#xff08;二&#xff09;hbase-site.xml三、配置环境变量四、复制jar包到lib文件夹五、修改regionservers文件六、分发安装包和配置文件七、启动Hbase八、验证HBase是否启…

尚硅谷前端ES6-ES11

ECMAScript 是由 Ecma 国际通过 ECMA-262 标准化得脚本程序设计语言。 1.let变量声明以及变量声明特性 <body><script>//let的声明let a , b10;//特性1&#xff1a;变量不能重复声明&#xff0c;避免命名污染// let star "罗翔"// let star "张…

Java | 浅谈多态中的向上转型与向下转型

文章目录&#x1f333;向上转型&#x1f4d5;概念明细&#x1f4aa;使用场景1&#xff1a;直接赋值&#x1f4aa;使用场景2&#xff1a;方法传参&#x1f4aa;使用场景3&#xff1a;方法返回&#x1f4aa;向上转型的优缺点&#x1f333;向下转型&#x1f529;向下转型解决【调用…

程序员拯救了一次地球

流浪地球2&#xff1a;程序员拯救了一次地球 顺便给我们讲了一个道理&#xff1a; 人类会谋划未来&#xff0c; 但关键的一步是靠勇气迈出去的 趣讲大白话&#xff1a;算得好不如胆量好 *********** 电影工业的皇冠是特效 国产电影的特效进步不小 时时刻刻&#xff0c;分分秒秒…

用户画像计算更新

3.1 用户画像计算更新 目标 目标 知道用户画像建立的流程应用 无 3.1.1 为什么要进行用户画像 要做精准推送同样可以使用多种推荐算法&#xff0c;例如&#xff1a;基于用户协同推荐、基于内容协同的推荐等其他的推荐方式&#xff0c;但是以上方式多是基于相似进行推荐。而构…

ROS移动机器人——ROS基础知识与编程

此文章基于冰达机器人进行笔记整理&#xff0c;使用的环境为其配套环境&#xff0c;可结合之前的ROS&#xff0c;赵虚左老师的文章结合进行观看&#xff0c;后期也会进行整合 1. ROS安装 &#xff08;1&#xff09;配置ubuntu的软件和更新&#xff0c;允许安装不经认证的软件…

JS手动触发PWA安装窗口

✅作者简介&#xff1a;人工智能专业本科在读&#xff0c;喜欢计算机与编程&#xff0c;写博客记录自己的学习历程。 &#x1f34e;个人主页&#xff1a;小嗷犬的博客 &#x1f34a;个人信条&#xff1a;为天地立心&#xff0c;为生民立命&#xff0c;为往圣继绝学&#xff0c;…

仿写Dubbo-初识Dubbo

概念 Dubbo 在Dubbo官网介绍到&#xff0c;Apache Dubbo 是一款 RPC 服务开发框架&#xff0c;用于解决微服务架构下的服务治理与通信问题。 RPC RPC&#xff08;Remote Procedure Call&#xff09;远程过程调用协议&#xff0c;一种通过网络从远程计算机上请求服务&#xff0c…

【Android】手机安装Termux运行nodejs学习Javascript编程入门

Termux 是运行在Android手机上的一个 Linux 终端模拟器&#xff0c;干什么都要输入命令执行&#xff0c;不像 Windows 操作系统桌面用鼠标点点点&#xff0c;这里主要介绍用它来学习Javascript编程入门&#xff0c;当然&#xff0c;这和小时候学过的C语言编程课入门一样的&…

C语言之程序设计概述

1.1.1 程序的概念 程序&#xff1a;算法 数据结构 程序设计方法 语言工具和环境数据结构&#xff1a;数据的类型和数据的组织方式算法&#xff1a;对数据操作的方法和步骤 1.1.2 程序设计语言的种类 第一代语言&#xff08;机器语言&#xff09;&#xff1a;执行效率高、…

【Leetcode每日一题】35.搜素插入位置|二分查找数组下标

&#x1f331;博主简介&#xff1a;大一计科生&#xff0c;努力学习Java中!热爱写博客~预备程序媛 &#x1f4dc;所属专栏&#xff1a;LeetCode每日一题–进击大厂 ✈往期博文回顾: 【JavaSE】保姆级教程|1万字10张图学会类与对象–建议收藏 &#x1f575;️‍♂️近期目标&…

【题解】2023牛客寒假算法基础集训营2

目录A. Tokitsukaze and abn (easy)思路B. Tokitsukaze and abn (medium)思路Tokitsukaze and abn (hard)思路D. Tokitsukaze and Energy Tree思路bfsdfsE. Tokitsukaze and Energy Tree思维F. Tokitsukaze and Gold Coins (easy)思路G. Tokitsukaze and Gold Coins (hard)H. T…

高效团队的gitlab flow最佳实践

当前git是大部分开发团队的首选版本管理工具&#xff0c;一个好的流程规范可以让大家有效地合作&#xff0c;像流水线一样有条不紊地进行团队协作。 业界包含三种flow&#xff1a; Git flowGithub flowGitlab flow 下面我们先来分析&#xff0c;然后再基于gitlab flow来设计一…

19、Javaweb案例-登录功能

项目导入 选择travel项目的pom.xml文件&#xff0c;点击ok&#xff0c;完成项目导入。需要等待一小会&#xff0c;项目初始化完成。 启动项目 方式一&#xff1a; 方式二&#xff1a;配置maven快捷启动 技术选型 Web层 Servlet&#xff1a;前端控制器html&#xff1a;视图Fi…

【c语言】数据结构-顺序表

主页&#xff1a;114514的代码大冒险 qq:2188956112&#xff08;欢迎小伙伴呀hi✿(。◕ᴗ◕。)✿ &#xff09; Gitee&#xff1a;庄嘉豪 (zhuang-jiahaoxxx) - Gitee.com 文章目录 目录 文章目录 前言 一、顺序表是什么&#xff1f; 二、项目功能的逐一实现&#xff08;基本&a…

Python-Flask-2023.1.22

1、WSGIweb server gateway interface一个框架定义的简单通用的接口Web服务器网关接口&#xff08;Python Web Server Gateway Interface&#xff0c;缩写为WSGI&#xff09;是为Python语言定义的Web服务器和Web应用程序或框架之间的一种简单而通用的接口。flask框架内有默认的…

手写vue及源码解析一 rollup环境的搭建

开篇 都手写源码了&#xff0c;那就顺便分析一下源码吧。 rollup环境的搭建 作为了解就行。需要使用rollup来编译我们自己手写的vue代码。 需要安装rollup,rollup的babel插件&#xff0c;以及babel核心和babel预设&#xff08;可以理解为初始化模板&#xff09;。 mkdir vu…

Java变量定义时候的注意事项

常量定义的基本注意事项 在JAVA语言中&#xff0c;主要利用final关键字&#xff0c;&#xff08;在Java类中灵活使用static关键字&#xff09;来定义常量。 当常量被设定后&#xff0c;一般情况下就不允许在进行更改了&#xff0c;如可以利用以下的形式来定义常量&#xff1a;…

仿写Dubbo-Java Socket

概念 socket 被翻译为“套接字”&#xff0c;socket是计算机之间进行通信的一种方式。通过socket可以实现端(端口)到端通信。Java的java.net包中提供了进行socket通信的类。主要使用ServerSocket和Socket类实现通信。 ServerSocket 服务端应用使用java.net.ServerSocket类来获取…

Node.js 操作MongoDB (Mongoose) 数据库

在讲Node.js通过使用mongoose模块来操作MongoDB数据库之前首先是关于MongoDB数据库的安装和MongoDB服务以及对MongoDB命令行的操作和可视化工具MongoDBCompass的一个基本使用&#xff1b;那么在这里已经准备好了关于MongoDB数据库的内容了&#xff1a; MongoDB数据库安装详细 &…