random——模块

本文详细介绍了Python中random模块的功能及使用方法,包括产生伪随机数、选择序列元素、序列混合等常用操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

random——产生伪随机数

模块用途

random 模块是为各种分布实现伪随机数发生器。

几乎模块中所有函数都依赖于基本函数random(),它在半开放范围[0.0,1.0)内产生一个统一的随机浮点数。Python使用Mersenne Twister作为核心生成器。它生成53位精度浮点数,周期为2**19937-1.C中的底层实现即快速又线程安全。

注:Mersenne Twister是存在的最广泛测试的随机数发生器之一。但是,这是完全确定性的,并不适用于所有目的,并且完全不适合加密的目的

警告:该模块的伪随机生成器不应用于安全目的。为了安全或加密使用

_randbelow()的部分源码

BPF = 53        
# 返回一个小于n的随机数(计算随机数的实例)
    def _randbelow(self, n, int=int, maxsize=1<<BPF, type=type,
                   Method=_MethodType, BuiltinMethod=_BuiltinMethodType):

        "Return a random int in the range [0,n).  Raises ValueError if n==0."

        random = self.random            # 将父类的random方法赋值给random
        getrandbits = self.getrandbits  # 将父类的getrandbits方法赋值给getrandbits

        # 如果原始的random()内置方法没有被覆盖 或者 提供了一个新的getrandbits() 才可以调用self.getrandbits
        if type(random) is BuiltinMethod or type(getrandbits) is Method:
             # 如果 random 是内置函数 或 getrandbits 是 方法

            # k 是 开始位置转换成二进制的长度
            k = n.bit_length()  # don't use (n-1) here because n can be 1
            # 计算 一个随机数
            r = getrandbits(k)          # 0 <= r < 2**k
            while r >= n:
                r = getrandbits(k)
            # 返回一个小于n的随机数
            return r

        # 如果复写了random()方法但是没有复写getrandbits()方法 我们只能用自己的random()方法
        if n >= maxsize:
            # 如果n >= maxsize (maxsize = 9007199254740992) 就调用random()方法
            _warn("Underlying random() generator does not supply \n"
                "enough bits to choose from a population range this large.\n"
                "To remove the range limitation, add a getrandbits() method.")
            return int(random() * n) # random() 方法 是 随机[0,1) 的一个数
        rem = maxsize % n
        limit = (maxsize - rem) / maxsize   # int(limit * maxsize) % n == 0
        r = random()    # r < liimit
        while r >= limit:
            r = random()
        return int(r*maxsize) % n  

随机整数

random.randrange(self, start, stop=None, step=1, _int=int)

  • start: 起始数值
    • stop=None:结束数值 默认为 None
    • step=1步长 默认为1
random.randrange(10)

​ ——产生一个[0,10)的随机整数

import random
print(random.randrange(10))

5

以下为randrange部分源码

 def randrange(self, start, stop=None, step=1, _int=int):
    istart = _int(start)
        if istart != start:
            raise ValueError("non-integer arg 1 for randrange()")
        # 如果stop是空 即 我们只传了一个参数即 random.randrange(10)
        if stop is None:
            if istart > 0:
                # 返回一个小于 start 的 随机数
                return self._randbelow(istart)
            raise ValueError("empty range for randrange()")

random.randrange(10)

如果我们传入的参数是一个大于0的数字,就会通过_randbelow(10)进行运算得到返回值

random.randrange(5,20)

​ ——产生一个[5,20)的随机整数

import random
print(random.randrange(5, 20))

7

以下是randrange部分源码

 def randrange(self, start, stop=None, step=1, _int=int):
        # stop argument supplied.
        istop = _int(stop)
        if istop != stop:
            raise ValueError("non-integer stop for randrange()")
        width = istop - istart # 范围 是一个整数
        if step == 1 and width > 0: # 如果步长等于1 且 范围大于零
            # 返回 一个 start + 小于范围的随机数
            return istart + self._randbelow(width) # _randbelow()方法见上面
        if step == 1:
            # 如果范围 <= 0 则抛出以下异常 具体示例 见 Lrandrange_E1
            raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width))

random.randrange(5,20)

如果我们传入的参数为x, y 且(y - x )> 0 就会通过x + _randbelow(y - x) 进行运算得到返回值

Lrandrange_E1

import random
print(random.randrange(1,1,1))

Traceback (most recent call last):
  File "D:/random_demo.py", line 20, in <module>
    print(random.randrange(1,1,1))
  File "D:/random_demo.py", line 198, in randrange
    raise ValueError("empty range for randrange() (%d,%d, %d)" % (istart, istop, width))
ValueError: empty range for randrange() (1,1, 0)
random.randrange(5,-1,-2)

​ ——产生(5,-1,-2)的随机数

import random
print(random.randrange(5,-1,-2))

3
random.randrange(5,20,5)

​ ——产生(5,20,5)的随机数

import random
print(random.randrange(5, 20, 5))


10

以下是randrange部分源码

 def randrange(self, start, stop=None, step=1, _int=int):
    istep = _int(step)
        if istep != step:
            raise ValueError("non-integer step for randrange()")

        # 要么 start < stop and istep > 0
        # 要么 start > stop and istep < 0
        # 其余情况报错
        if istep > 0:
            # width = istop - istart
            n = (width + istep - 1) // istep 
        elif istep < 0:
            n = (width + istep + 1) // istep 
        else:
            raise ValueError("zero step for randrange()")

        if n <= 0:
            raise ValueError("empty range for randrange()")
        # 返回 start + 步长 * 小于n的随机整数
        return istart + istep*self._randbelow(n)

如果我们传入的参数为为x, y, z

  • ( z < 0 )且(y - x )< 0 就会通过x + z * _randbelow((y - x + 1) // z) 进行运算得到返回值
  • ( z > 0 )且(y - x )> 0 就会通过x + z * _randbelow((y - x - 1) // z) 进行运算得到返回值
    • ((y - x + 1) // z) 是计算了 可取的范围(其实就是计算了[x, y)这个范围中有最多可取到多少个z)
    • 根据这个数取一个小于它的随机数然后乘步长 + x

random.randint(a,b)

返回一个随机整数N使得。别名 。a <= N <= b``randrange(a, b+1)

def randint(self, a, b):
    """Return random integer in range [a, b], including both end points.
    """

    return self.randrange(a, b+1)

so~ randint() 其实就是调用了 randrange()方法 也就是一个简化版的randrange()

序列函数

random.choice(self, seq)

​ ——在一个非空的序列中选择一个元素

import random
print(random.choice([1,2,3]))

1

源码如下

def choice(self, seq):
    try:
        # 选择一个随机索引
        i = self._randbelow(len(seq))
    except ValueError:
        # 如果序列为空 则抛出异常
        raise IndexError('Cannot choose from an empty sequence')
    # 通过索引找到随机的元素
    return seq[i]

random.choice([1,2,3])

在这个list列表中 根据列表的长度随机算出一个小于列表长度的数作为索引,返回该索引的值

random.shuffle(self, x, random=None)

将序列x随机混合(将x随机打乱)

import random
l = [12,11,10]
random.shuffle(l)
print(l)


[12, 10, 11]

源码如下

def shuffle(self, x, random=None):
        ''' x 列表(可迭代对象)
            random 是一个 计算随机数的方法
        '''
    # random 为空 即 我们没有手动传入一个计算随机数的方法
    if random is None
        # 赋予self._randbelow方法 一个别名 randbelow
        randbelow = self._randbelow

        # 循环 len 次每次将索引为i的 值 和 索引为 一个小于i的随机整数的值进行替换
        for i in reversed(range(1, len(x))):
            # 通过self._randbelow方法进行计算随机数得到j的值
            j = randbelow(i+1)
            # 交换 索引为i 和索引为j的值
            x[i], x[j] = x[j], x[i]

    # 如果我们手动传入了一个随机数方法
    else:
        _int = int
        # 循环 len 次每次将索引为i的 值 和 索引为 一个小于i的随机整数 的值进行替换
        for i in reversed(range(1, len(x))):
            # 通过我们手动传入的随机数方法的结果 * (i+1) 得到j的值
            j = _int(random() * (i+1))
            # 交换 索引为i 和索引为j的值
            x[i], x[j] = x[j], x[i]

shuffle方法其实是不断进行两两索引位置的值进行交换 达到打乱顺序的

并且它是在原本的列表上进行打乱的,而没有新的列表生成

random.sample(self, population, k)

​ ——返回从总体序列或集合中选择的唯一元素的k长度列表。用于无需更换的随机抽样。

import random
l = [1,2,3,4,5]
l2 = random.sample(l,2)
print(l2)


[4, 3]

源码如下

    def sample(self, population, k):
        # 判断population是否是可使用sample的类型(如果是set转成tuple 如果是tuple、list就继续运行 如果是dict直接报错)
        if isinstance(population, _Set):
            population = tuple(population)
        if not isinstance(population, _Sequence):
            raise TypeError("Population must be a sequence or set.  For dicts, use list(d).")
        # self._randbelow 命名一个别名randbelow
        randbelow = self._randbelow
        # 计算population的长度
        n = len(population)
        # 如果k >=n 或者<=0 就报错, k是选择元素的长度
        if not 0 <= k <= n:
            raise ValueError("Sample larger than population or is negative")
        # 设置默认值
        result = [None] * k
        setsize = 21        # 默认为小集合
        # 如果k大于5则认为 是一个大集合 否则是小集合
        if k > 5:
            setsize += 4 ** _ceil(_log(k * 3, 4)) # table size for big sets

        # 如果是小集合(An n-length list is smaller than a k-length set)
        if n <= setsize:
            # 将population强转成list
            pool = list(population)
            # 这里!!! 其实就是为了每次都可以选出列表中的一个数(选出一个之前没有选择过的数) 然后依次赋给result 这个之前设置的默认值为None 的列表
            for i in range(k):         # invariant:  non-selected at [0,n-i)
                # 随机一个 n-i 的整数当作 下标赋给j
                j = randbelow(n-i)
                # 这下面两句就是在 把选中的数替换成倒置位的数 (因为倒置位的数一直无法取到所以将其替换到前面 )
                result[i] = pool[j]     # 将值赋给  result列表
                pool[j] = pool[n-i-1]   # move non-selected item into vacancy

        # 猜测是因为大集合如果转换成list太过于占空间 所以单独 拿了出来
        else:
            # 创建了一个set 对象 
            selected = set()
            selected_add = selected.add # 给set对象的add方法 赋值一个别名

            for i in range(k):
                j = randbelow(n) # 一个小于n的随机数 并赋给j 当作下标

                # 如果j 不在selected中,即 我们没有选择过 下标为j的数,就跳过while循环
                # 如果在selected中,即 我们曾经选择到 下标为j的数, 则重新取随机数 直到,选择一个从来没有使用过的j
                while j in selected:
                    j = randbelow(n)

                selected_add(j)     # 将j添加到集合中
                result[i] = population[j] # 将值赋给  result列表
        return result

簿记功能

random.seed(self, a=None, version=2)

​ ——seed() 方法改变随机数生成器的种子,可以在调用其他随机模块函数之前调用此函数

改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。

import random
random.seed(0)
print(random.random())
random.seed(0)
print(random.random())
0.8445167133186481
0.8445167133186481

源码如下

def seed(self, a=None, version=2):
    # a -- 改变随机数生成器的种子seed。如果你不了解其原理,你不必特别去设定seed,Python会帮你选择seed。
    # 默认调用第二个方式 version = 2 

    # 是方案1 并且 a是str 或 bytes 
    if version == 1 and isinstance(a, (str, bytes)):
        # 如果 a 不为None 则 进行运算 否则x 为0
        x = ord(a[0]) << 7 if a else 0
        for c in a:
            x = ((1000003 * x) ^ ord(c)) & 0xFFFFFFFFFFFFFFFF
        x ^= len(a)
        a = -2 if x == -1 else x
    # 是方案2 并且 a是str 或 bytes 或 bytearray
    if version == 2 and isinstance(a, (str, bytes, bytearray)):
        # 如果a是字符串则 转成bytes类型
        if isinstance(a, str):
            a = a.encode()
        # a 进行加密并进行拼接
        a += _sha512(a).digest()
        a = int.from_bytes(a, 'big')

    # 调用父类的seed(父类中根据当前时间进行生成)
    super().seed(a)
    self.gauss_next = None

seed( ) 用于指定随机数生成时所用算法开始的整数值,如果使用相同的seed( )值,则每次生成的随即数都相同,如果不设置这个值,则系统根据时间来自己选择这个值,此时每次生成的随机数因时间差异而不同。

<think>我们正在讨论YOLOv5官方代码中`random_perspective`函数的参数调整范围。这个函数位于`utils/augmentations.py`文件中,用于实现图像的空间变换增强,包括旋转、平移、缩放、错切、透视变换等。这些变换的参数在代码中以超参数的形式出现,通常通过一个包含多个参数的列表进行配置。 根据YOLOv5的官方代码和超参数配置文件(如`data/hyps/hyp.scratch-low.yaml`等),我们可以找到与`random_perspective`相关的参数及其默认值。这些参数在训练时被用于数据增强,以提高模型的鲁棒性。 ### 1. **random_perspective参数列表** 在`random_perspective`函数中,主要包含以下参数(以`hyp.scratch-low.yaml`为例): ```yaml # 空间变换增强参数 (random_perspective) degrees: 0.0 # 旋转角度范围 translate: 0.1 # 平移比例(相对于图像尺寸) scale: 0.5 # 缩放比例范围 [1-scale, 1+scale] shear: 0.0 # 错切角度范围 perspective: 0.0 # 透视变换强度 [0, 0.001] ``` ### 2. **参数调整范围及作用** | 参数名 | 默认值 | 推荐调整范围 | 作用 | |--------|--------|--------------|------| | **degrees** | 0.0 | $[0.0, 45.0]$ | 控制图像旋转角度范围(单位:度),随机在$[-degrees, degrees]$区间选择旋转角度 | | **translate** | 0.1 | $[0.0, 0.2]$ | 控制图像平移范围(相对于图像宽高的比例),平移量在$[-translate*width, translate*width]$和$[-translate*height, translate*height]$中随机 | | **scale** | 0.5 | $[0.0, 0.9]$ | 控制图像缩放范围,缩放因子在$[1-scale, 1+scale]$之间随机选择 | | **shear** | 0.0 | $[0.0, 10.0]$ | 控制图像错切角度范围(单位:度),在$[-shear, shear]$区间随机选择错切角度 | | **perspective** | 0.0 | $[0.0, 0.001]$ | 控制透视变换强度,值越大透视效果越强(通常设置为0.0到0.001之间) | ### 3. **参数调整建议** - **degrees**:对于旋转不变性要求高的场景(如航拍图像),可增大至30.0-45.0;对于自然场景,通常0.0-10.0即可。 - **translate**:对于目标位置变化较大的场景(如运动目标),可增大至0.2;一般场景0.1左右。 - **scale**:对于尺度变化大的场景(如不同距离的目标),可增大至0.9;但注意过大可能导致目标太小而难以检测。 - **shear**:对于存在视角倾斜的场景(如斜视拍摄),可增大至5.0-10.0;一般场景0.0即可。 - **perspective**:对于需要模拟远近透视效果的场景(如道路目标检测),可设置为0.0005-0.001;一般场景0.0即可。 ### 4. **代码实现位置** 在`utils/augmentations.py`中的`random_perspective`函数: ```python def random_perspective(im, targets=(), segments=(), degrees=10, translate=.1, scale=.1, shear=10, perspective=0.0, border=(0, 0)): # 具体实现代码... # 参数说明: # degrees: 旋转角度范围 # translate: 平移比例 # scale: 缩放比例范围 # shear: 错切角度范围 # perspective: 透视变换参数 ``` ### 5. **超参数配置文件示例** 在`data/hyps/hyp.scratch-low.yaml`中: ```yaml # 空间变换增强参数 degrees: 0.0 # 旋转角度范围 (+/- deg) translate: 0.1 # 平移比例 (+/- fraction) scale: 0.5 # 缩放比例 (log2 scale zoom) shear: 0.0 # 错切角度 (+/- deg) perspective: 0.0 # 透视变换参数 (+/- fraction), range 0-0.001 ``` ### 6. **调整注意事项** 1. **参数协同调整**:增大旋转、平移、缩放等参数会显著增加数据多样性,但也可能使训练难度加大,需配合调整学习率等参数。 2. **目标边界处理**:当旋转、平移等参数较大时,可能将目标移出图像边界,此时需配合`mosaic`增强和`copy_paste`增强使用。 3. **小目标检测**:避免使用过大的缩放参数(如scale>0.9),否则可能导致小目标被过度缩小。 ### 7. **参数关系图示** ``` 空间变换流程: 1. 旋转: 围绕图像中心旋转随机角度 2. 平移: 沿x/y轴随机移动 3. 缩放: 随机放大或缩小 4. 错切: 沿x/y轴随机倾斜 5. 透视: 模拟3D视角变化 ``` --- §§相关问题§§: 1. YOLOv5中如何调整mosaic数据增强的参数? 2. random_perspective与copy_paste增强如何配合使用? 3. 如何根据数据集特性选择合适的数据增强组合?</think>### YOLOv5官方代码中`random_perspective`参数调整范围详解 在YOLOv5的数据增强模块中,`random_perspective`是实现空间变换增强的核心函数,位于`utils/augmentations.py`文件中。以下是其关键参数及其调整范围: #### 1. **核心参数及默认值** | 参数名 | 默认值 | 作用 | |--------|--------|------| | **degrees** | 0.0 | 旋转角度范围(单位:度) | | **translate** | 0.1 | 平移比例(相对于图像尺寸) | | **scale** | 0.5 | 缩放比例范围 | | **shear** | 0.0 | 错切角度范围(单位:度) | | **perspective** | 0.0 | 透视变换强度 | #### 2. **推荐调整范围** | 参数 | 安全范围 | 典型应用场景 | 调整影响 | |------|----------|--------------|----------| | **degrees** | $[-45, 45]$ | 旋转增强<br>(航拍图像增强) | ↑ 增大:提升旋转鲁棒性<br>↓ 减小:降低形变风险 | | **translate** | $[0.0, 0.2]$ | 目标位置偏移<br>(运动模糊模拟) | ↑ 增大:增强位置不变性<br>↓ 减小:保持原始位置 | | **scale** | $[0.1, 0.9]$ | 尺度变化<br>(多尺度目标检测) | ↑ 增大:增强尺度鲁棒性<br>↓ 减小:保持原始尺寸 | | **shear** | $[-30, 30]$ | 斜切变换<br>(视角倾斜补偿) | ↑ 增大:模拟视角倾斜<br>↓ 减小:减少几何失真 | | **perspective** | $[0.0, 0.001]$ | 3D透视效果<br>(道路场景增强) | ↑ 增大:增强深度感知<br>↓ 减小:保持平面性 | #### 3. **代码实现位置** 在`utils/augmentations.py`中的函数定义: ```python def random_perspective(im, degrees=10, # 旋转角度范围 translate=.1, # 平移比例 scale=.1, # 缩放比例 shear=10, # 错切角度 perspective=0.0, # 透视强度 border=(0, 0)): # 核心变换矩阵计算 M = get_transform_matrix(im.shape, degrees, translate, scale, shear, perspective) # 应用透视变换... ``` #### 4. **超参数配置文件** 在`data/hyps/hyp.scratch-low.yaml`中的默认配置: ```yaml # 空间变换增强参数 degrees: 0.0 # 旋转角度范围 (+/- deg) translate: 0.1 # 平移比例 (+/- fraction) scale: 0.5 # 图像缩放因子 (log2 scale) shear: 0.0 # 错切角度 (+/- deg) perspective: 0.0 # 透视变换系数 ``` #### 5. **场景化调整建议** | 应用场景 | 推荐参数组合 | 原理 | |----------|--------------|------| | 道路目标检测 | `degrees=5, perspective=0.0007` | 模拟行车视角变化 | | 航拍图像 | `degrees=30, shear=15` | 补偿无人机拍摄角度 | | 文档识别 | `shear=0, perspective=0` | 避免文本形变 | | 小目标检测 | `scale=0.9, translate=0.05` | 增强位置多样性 | > **调整注意事项**: > 1. 透视变换强度`perspective`超过0.005可能导致严重失真 > 2. 组合使用Mosaic增强时,建议降低`degrees`和`shear`值 > 3. 可通过超参数进化自动优化: > ```bash > python train.py --evolve > ``` #### 6. **参数关系图示 ``` 空间变换流程: 1. 旋转 → 2. 平移 → 3. 缩放 → 4. 错切 → 5. 透视 (变换顺序影响最终效果) ``` ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值