PyTorch深度学习实战 | 手算卷积网络(Resnet-18)

简介: ResNet-18是解决深层网络梯度消失与退化问题的经典模型,核心在于残差连接(Shortcut):让输入X直接跳跃传递,与卷积学习的残差F(X)相加(F(X)+X),实现恒等映射。其含4个stage、18层可训练层,每个BasicBlock由两个3×3卷积+BN+ReLU构成,并通过1×1卷积适配尺寸/通道差异,显著提升深层网络训练稳定性与性能。(239字)

 引入

       在深度学习的世界里,我们经常会听到一个问题:网络越深,效果一定越好吗?

     其实,答案是否定的!如果你直接把网络层数加深,模型的训练反而可能变得更难,甚至出现

梯度消失退化问题(深度越大,训练效果可能反而变差)。

      ResNet(Residual Network,残差网络)就是为了解决这个问题而诞生的,它的核心思想是

加一条“捷径”,让数据可以跳跃传播!

     ResNet-18 是 ResNet 家族 的一员,它的数字 “18” 指的是网络总共有 18 层(主要是包含可学

习参数的卷积层和全连接层)。ResNet 的核心特点是 “残差连接”(Residual Connection),它能

让信息在网络中 跳跃 传播,避免梯度消失,让深层网络更容易训练。

     ResNet-18的网络简图如下图(假设网络的输入的张量的形状为3 × 64 × 64 ),如图resnet的结

构分为四个stage,完整的ResNet-18的结构图在最后。

image.gif

ResNet-18 的基本架构如下:

🔹 这里的 残差块(Residual Block) 负责做特征提取,每个块内部包含两个 3×3 卷积。

🔹 跳跃连接(Shortcut)让数据既可以通过卷积层,也可以 直接“抄近路” 传递到下一层。

image.gif


残差连接

假设 输入是 X,而普通 CNN 的目标是直接学一个映射 F(X),但 ResNet 让网络学的是 F(X) -

X,这样一来,我们可以重写成:

image.gif

   F(X) 是卷积层学习的内容(残差)。

   X 是输入的跳跃连接(shortcut)

   F(X) + X 就是输出。

      残差块通常包含两个卷积层,每个卷积层后面跟着批量归一化(Batch Normalization)

活函数(如ReLU)。这些层负责提取和转换输入特征。

为啥残差块有这两种模式呐?

    image.gif

    现在我们手动模拟一下残差块的运算:

    【1】给定3 ×3的输入张量

    【2】通过第一个卷积层,批量归一化,激活函数(ReLU)(负数变成0)

    【3】通过第二个卷积层,批量归一化,激活函数(ReLU)(负数变成0)得到 F(X)

    【4】F(X)+ X 得到最后的输出

    image.gif

               F(X)+ X 可以直接相加的前提的是两者的大小一样,通道数一样

             所以当两者不一样的时候我们需要增加一个分支(1×1的卷积进行调整)(需要 shortcut 的情况)

                可以通过设置1×1的卷积的卷积核的数量调整通道数

                可以通过设置1×1的卷积的填充padding=0调整大小

    啥时侯两者不一样鸭?

        步长 ≠ 1 时,意味着 输入的尺寸会缩小,比如 stride=2 时 H × W 变为 H/2 × W/2。

    由于 x 形状变小了,我们需要用 1×1 卷积 让 x 也变小,以便与 F(x) 匹配。

    in_channels != out_channels:

       输入通道数 ≠ 输出通道数,意味着 x 的通道数 不能直接加到 F(x) 上。

    例如:之前的特征图有 64 个通道,当前块的 F(x) 计算出了 128 个通道。

    这样 x 是 64 通道,而 F(x) 是 128 通道,无法相加。解决办法:用 1×1 卷积 升维/降维,把 x 变

    成 F(x) 一样的通道数。


    残差块的实现

    代码实现

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    # ===== 定义 BasicBlock =====
    class BasicBlock(nn.Module):
        expansion = 1
        def __init__(self, in_channels, out_channels, stride=1):
            super(BasicBlock, self).__init__()
            self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
            self.bn1 = nn.BatchNorm2d(out_channels)
            self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
            self.bn2 = nn.BatchNorm2d(out_channels)
            # 如果尺寸或通道不同,调整 shortcut
            self.shortcut = nn.Sequential()
            if stride != 1 or in_channels != out_channels:
                self.shortcut = nn.Sequential(
                    nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                    nn.BatchNorm2d(out_channels)
                )
        def forward(self, x):
            print("输入 x 形状:", x.shape)
            identity = self.shortcut(x)
            if len(self.shortcut) > 0:
                print("shortcut 调整后形状:", identity.shape)
            else:
                print("shortcut 未调整(直接跳接)")
            out = self.conv1(x)
            print("conv1 输出:", out.shape)
            out = self.bn1(out)
            print("bn1 输出:", out.shape)
            out = F.relu(out)
            print("relu1 输出:", out.shape)
            out = self.conv2(out)
            print("conv2 输出:", out.shape)
            out = self.bn2(out)
            print("bn2 输出:", out.shape)
            out += identity
            print("残差相加后:", out.shape)
            out = F.relu(out)
            print("relu2 输出:", out.shape)
            print("-" * 50)
            return out
    # ===== 二、创建一个实例并测试 =====
    # 情况1:输入输出通道相同,不降采样
    block1 = BasicBlock(in_channels=3, out_channels=3, stride=1)
    x1 = torch.randn(1, 3, 32, 32)  # batch=1, 通道=3, 尺寸=32x32
    print("===== 测试 block1(stride=1)=====")
    out1 = block1(x1)
    print("最终输出:", out1.shape)
    # 情况2:输入输出通道不同,降采样
    block2 = BasicBlock(in_channels=3, out_channels=4, stride=2)
    x2 = torch.randn(1, 3, 32, 32)
    print("\n===== 测试 block2(stride=2)=====")
    out2 = block2(x2)
    print("最终输出:", out2.shape)

    image.gif

    现在我们开始图解每一步的实现过程:

    情况1:输入输出通道相同,不降采样

    首先,经过第一个卷积,归一化,和激活函数,大小仍然是3*32*32

    image.gif

    然后我们开始经过第二个卷积,归一化,大小仍然是3*32*32, 到这里为止,我们的第一个支路已经计算结束了。

    image.gif

    然后我们开始计算残差那个分支:由于这个我们这个残差模块的输出通道数和输入通道数一样,步

    长也是1,所以不需要残差分支的输出就是原始的X。然后把X和上面的另一个分支的F(X)逐个

    元素相加就行。然后再经过一个Relu激活函数的 处理。残差模块就计算结束了。

    image.gif

    情况2:输入输出通道不相同,降采样

    首先,经过第一个卷积(4个大小是3*3,步长为2的卷积)归一化,和激活函数,由于卷积核的个

    数是4,所以最后的输出通道数也是4,然后步长为2,所以最后图片的大小会会变成原来的一半,

    最后的大小是4*16*16。

    image.gif

    然后我们开始经过第二个卷积((4个大小是3*3,步长为1的卷积),归一化,大小仍然是

    4*16*16,到这里为止,我们的第一个支路已经计算结束了。

    image.gif

    然后我们开始计算残差那个分支:由于这个我们这个残差模块的输出通道数和输入通道数 不一

    样,所以残差分支的输出就是原始的X经过shortcut之后的输出(1*16*16)

    image.gif

    最终的输出就是原始分支的输出(F(x))和残差分支的输出(X)的相加。然后再经过Relu激活函数之

    后得到4*16*16大小的特征图。

    image.gif


    make_layer(堆叠的多个 BasicBlock)

     我们知道,Resnet一共包含4个layer,每个layer中含有多个num_blocks,为了更加简洁的表示,

    我们可以使用一个layer函数,集成多个残差层,简化表示。

    def _make_layer(self, out_channels, num_blocks, stride):
        layers = []  # 创建一个空列表,用于存储这一层的 BasicBlock
        # 第一个 BasicBlock 的 stride 为输入参数 stride,这里是第一个块
        layers.append(BasicBlock(self.in_channels, out_channels, stride))
        # 更新当前通道数
        self.in_channels = out_channels
        # 接下来的 num_blocks - 1 个 BasicBlock 都使用 stride=1
        for _ in range(1, num_blocks):
            layers.append(BasicBlock(self.in_channels, out_channels, stride=1))
        # 将所有的 BasicBlock 堆叠成一个 nn.Sequential 模块
        return nn.Sequential(*layers)

    image.gif

    初始化 layers 列表

         layers 列表用于存储构建的每一个 BasicBlock,最终返回的是一个 nn.Sequential(一个有序

    的模块容器)。

    添加第一个 BasicBlock:

         layers.append(BasicBlock(self.in_channels, out_channels, stride))

       第一个 BasicBlock 使用了传入的 stride,并且将当前的输入通道数(self.in_channels)作为输

    入通道数,输出通道数为 out_channels。stride 影响卷积操作的步长,通常第一个 BasicBlock 需

    要通过卷积来改变特征图的尺寸(例如降采样)。

    更新当前通道数:

    self.in_channels = out_channels

               每次添加一个 BasicBlock 后,输入的通道数变为该 BasicBlock 输出的通道(out_channels)。

    添加后续的 BasicBlock:

    for _ in range(1, num_blocks):

         从第 2 个 BasicBlok 开始,使用 stride=1,即不改变特征图尺寸。这里是为了保持相同的空间

    分辨率,通常在残差网络的后续块中使用步长为 1 来保证特征图尺寸不变。

    返回 nn.Sequential:

    return nn.Sequential(*layers)

           最后通过 nn.Sequential 将所有的 BasicBlock 按顺序组合成一层(layer)。nn.Sequential 会

    按照列表中的顺序依次执行每个 BasicBlock。

    举一个简单的例子

    # ---------- 包含 _make_layer 的简单 ResNet 片段 ----------
    class MiniResNet(nn.Module):
        def __init__(self):
            super(MiniResNet, self).__init__()
            self.in_channels = 3
            # 使用 _make_layer 创建两层:第一层不降采样(保持 64 通道),第二层降采样并将通道提升到 128
            self.layer1 = self._make_layer(out_channels=64, num_blocks=2, stride=1)
        def _make_layer(self, out_channels, num_blocks, stride):
            layers = []
            layers.append(BasicBlock(self.in_channels, out_channels, stride))
            self.in_channels = out_channels
            for _ in range(1, num_blocks):
                layers.append(BasicBlock(self.in_channels, out_channels, stride=1))
            return nn.Sequential(*layers)
        def forward(self, x):
            print("input:", x.shape)
            x = self.layer1(x)
            print("after layer1:", x.shape)  # 64 通道, 空间尺寸不变
            return x
    # ---------- 测试 ----------
    model = MiniResNet()
    # 假设输入是常见的 32x32 RGB 图像
    inp = torch.randn(1, 3, 32, 32)
    out = model(inp)

    image.gif



    完整代码

    import torch
    import torch.nn as nn
    import torch.nn.functional as F
    class BasicBlock(nn.Module):
        def __init__(self, in_channels, out_channels, stride=1):
            super(BasicBlock, self).__init__()
            self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=stride, padding=1, bias=False)
            self.bn1 = nn.BatchNorm2d(out_channels)
            self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1, bias=False)
            self.bn2 = nn.BatchNorm2d(out_channels)
            
            self.shortcut = nn.Sequential()
            if stride != 1 or in_channels != out_channels:
                self.shortcut = nn.Sequential(
                    nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=stride, bias=False),
                    nn.BatchNorm2d(out_channels)
                )
        
        def forward(self, x):
            out = F.relu(self.bn1(self.conv1(x)))
            out = self.bn2(self.conv2(out))
            out += self.shortcut(x)
            return F.relu(out)
    class ResNet18(nn.Module):
        def __init__(self, num_classes=2):
            super(ResNet18, self).__init__()
            self.in_channels = 64
            self.conv1 = nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1, bias=False)
            self.bn1 = nn.BatchNorm2d(64)
            self.layer1 = self._make_layer(64, 2, stride=1)
            self.layer2 = self._make_layer(128, 2, stride=2)
            self.layer3 = self._make_layer(256, 2, stride=2)
            self.layer4 = self._make_layer(512, 2, stride=2)
            self.avgpool = nn.AdaptiveAvgPool2d((1, 1))
            self.fc = nn.Linear(512, num_classes)
        
        def _make_layer(self, out_channels, num_blocks, stride):
            layers = []
            layers.append(BasicBlock(self.in_channels, out_channels, stride))
            self.in_channels = out_channels
            for _ in range(1, num_blocks):
                layers.append(BasicBlock(self.in_channels, out_channels, stride=1))
            return nn.Sequential(*layers)
        
        def forward(self, x):
            print("输入形状: ", x.shape)
            
            out = self.conv1(x)
            print("conv1输出: ", out.shape)
            out = self.bn1(out)
            print("bn1输出:   ", out.shape)
            out = F.relu(out)
            print("relu输出:  ", out.shape)
            
            out = self.layer1(out)
            print("layer1输出:", out.shape)
            
            out = self.layer2(out)
            print("layer2输出:", out.shape)
            
            out = self.layer3(out)
            print("layer3输出:", out.shape)
            
            out = self.layer4(out)
            print("layer4输出:", out.shape)
            
            out = self.avgpool(out)
            print("avgpool输出:", out.shape)
            
            out = torch.flatten(out, 1)
            print("flatten输出:", out.shape)
            
            out = self.fc(out)
            print("fc输出:    ", out.shape)
            
            return out
    # 测试网络(打印结构+输出形状)
    if __name__ == "__main__":
        model = ResNet18(num_classes=2)
        print("="*50)
        print("ResNet18 网络结构:")
        print(model)  # 打印网络结构
        print("="*50)
        
        x = torch.randn(1, 3, 32, 32)  # 输入:1张3通道32x32图像
        print("\n各层输出形状:")
        model(x)

    image.gif


    ==================================================

    ResNet18 网络结构:

    ResNet18(

     (conv1): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

     (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

     (layer1): Sequential(

       (0): BasicBlock(

         (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential()

       )

       (1): BasicBlock(

         (conv1): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential()

       )

     )

     (layer2): Sequential(

       (0): BasicBlock(

         (conv1): Conv2d(64, 128, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential(

           (0): Conv2d(64, 128, kernel_size=(1, 1), stride=(2, 2), bias=False)

           (1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         )

       )

       (1): BasicBlock(

         (conv1): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential()

       )

     )

     (layer3): Sequential(

       (0): BasicBlock(

         (conv1): Conv2d(128, 256, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential(

           (0): Conv2d(128, 256, kernel_size=(1, 1), stride=(2, 2), bias=False)

           (1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         )

       )

       (1): BasicBlock(

         (conv1): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential()

       )

     )

     (layer4): Sequential(

       (0): BasicBlock(

         (conv1): Conv2d(256, 512, kernel_size=(3, 3), stride=(2, 2), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential(

           (0): Conv2d(256, 512, kernel_size=(1, 1), stride=(2, 2), bias=False)

           (1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         )

       )

       (1): BasicBlock(

         (conv1): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn1): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (conv2): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1), bias=False)

         (bn2): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True, track_running_stats=True)

         (shortcut): Sequential()

       )

     )

     (avgpool): AdaptiveAvgPool2d(output_size=(1, 1))

     (fc): Linear(in_features=512, out_features=2, bias=True)

    )

    ==================================================


    各层输出形状:

    输入形状:  torch.Size([1, 3, 32, 32])

    conv1输出:  torch.Size([1, 64, 32, 32])

    bn1输出:    torch.Size([1, 64, 32, 32])

    relu输出:   torch.Size([1, 64, 32, 32])

    layer1输出: torch.Size([1, 64, 32, 32])

    layer2输出: torch.Size([1, 128, 16, 16])

    layer3输出: torch.Size([1, 256, 8, 8])

    layer4输出: torch.Size([1, 512, 4, 4])

    avgpool输出: torch.Size([1, 512, 1, 1])

    flatten输出: torch.Size([1, 512])

    fc输出:     torch.Size([1, 2])

    目录
    相关文章
    |
    1月前
    |
    机器学习/深度学习 存储 人工智能
    图解人工智能的数学基础(线性代数)
    本文系统讲解线性代数核心概念,涵盖向量(定义、几何/坐标表示、内积)、矩阵(含义、运算、秩、逆、相似、分解)、行列式(几何意义与变换关系)、线性方程组、特征值与特征向量、二次型、向量空间及范数等,强调其在AI与神经网络中的实际应用。
    291 7
    |
    1月前
    |
    人工智能 API iOS开发
    零门槛配置指南:借助DeepCodex实现Codex无缝对接DeepSeek大模型,让AI编程助手自由切换模型
    在当下的编程领域,AI编程助手已经成为开发者提升编码效率、排查代码漏洞、学习新语法的核心工具。Codex桌面端凭借出色的代码理解、生成与调试能力,收获了大量开发者的青睐。不过不少用户在使用过程中都会产生同一个想法:将Codex默认的底层模型替换为日常使用更顺手的DeepSeek模型。但二者采用了不同的接口协议,普通用户想要手动完成协议适配、接口配置、模型切换等一系列操作,不仅步骤繁琐,还极易因参数配置错误导致调用失败,对于编程新手而言更是难以独立完成。为了解决这一痛点,DeepCodex应运而生,它通过在本地搭建轻量级桥接服务,自动完成两大模型之间的协议转换,同时提供可视化命令行菜单,实现一键
    878 0
    |
    1月前
    |
    存储 人工智能 自然语言处理
    破解 AI 搜索“效果与成本”双重困境:阿里云 Elasticsearch 向量混合检索最佳实践揭秘
    阿里云ES发布向量混合检索最佳实践:融合BM25与kNN,通过BBQ量化(降本95%)、FalconSeek引擎(性能提升7倍)及OpenStore存算分离,兼顾语义精度与成本效益,支持企业级安全合规与AI Native演进。
    321 4
    |
    1月前
    |
    机器学习/深度学习 自动驾驶 PyTorch
    PyTorch深度学习实战 |SegNet
    CamVid_11是面向自动驾驶的语义分割数据集,含700+张精准标注图像,划分为训练/验证/测试集。涵盖道路、车辆、行人等11类场景目标(含背景共12类),支持SegNet等模型训练与评估。
    185 3
    |
    1月前
    |
    人工智能 自然语言处理 计算机视觉
    人工智能|大白话Meshed-Memory Transformer
    M2Transformer是一种图像描述生成模型,由三部分构成:骨干编码器(Faster R-CNN)提取区域特征;记忆增强编码器(Transformer)对特征进行语义细化;网格解码器(Transformer)将增强特征转化为自然语言描述。结构清晰、层次分明,兼顾准确性与可解释性。(239字)
    190 4
    |
    1月前
    |
    存储 人工智能 自然语言处理
    Skills实战:从0到1封装一个“登录鉴权”Skill,拿来即用
    本文直击AI Agent落地痛点——登录鉴权失效、状态丢失、提示词不可靠。提出以“Skill”替代传统提示词工程:将动态认证逻辑(如Token获取/刷新/存储)封装为可复用、带状态管理的代码模块,实现跨会话稳定调用。实战拆解Skill四要素,揭示其如何让AI“一次登录,全程无忧”。
    |
    15天前
    |
    域名解析 缓存 网络协议
    网站搭建网络配置-深入理解 DNS 解析与 CNAME 别名记录
    在企业级网站搭建与网络基础设施建设中,**域名系统(DNS,Domain Name System)** 是连接用户和网站源站服务器之间最核心的“数字纽带”。 通俗地说,计算机在网络世界中只能通过复杂的 IP 地址(如 `192.168.1.1`)来互相识别和通信。然而,对于普通访客和搜索引擎爬虫来说,记忆 IP 地址是几乎不可能的,人们更习惯于输入简单、易记的域名(如 `www.qxgro.com`)。DNS 的核心使命,就是充当网络世界的“电话本”,近乎瞬时地将人类可读的域名解析为计算机可识别的二进制 IP 地址。
    |
    1月前
    |
    人工智能 资源调度 调度
    AI时代,大学生应该提前准备什么?
    AI时代,大学生面临就业重塑与能力升级的双重挑战。本文聚焦认知重构、三大核心能力(统筹力、技术力、实战力)及行动路径,倡导从“工具使用者”进阶为“AI决策者”,以T型+AI复合素养应对变革,在人机协同中抢占未来先机。
    316 8
    |
    1月前
    |
    人工智能 自然语言处理 安全
    阿里云Coding Plan和Token Plan团队版有啥区别?百炼ai大模型平台如何选择?
    阿里云百炼提供Coding Plan(个人向,按次计费、限频次、仅文本模型)与Token Plan团队版(企业向,按Credits计费、无频次限制、支持文本+图像多模态),适配不同场景与安全合规需求。免费领取7000万tokens:https://t.aliyun.com/U/fPVHqY
    372 6
    |
    1月前
    |
    存储 人工智能 缓存
    AI不稳定不是工程Bug,是一场系统性误读——意图共鸣科技行业洞察
    过去三年AI狂卷参数与算力,却困于“Demo惊艳、上线翻车”。症结在于误读“AI稳定性”——它非传统软件不宕机,而是大模型在行为分寸、长期记忆、责任可溯、商业可持续四维的结构性缺失。意图共鸣科技正深耕此深水区。
    219 6