【机器学习】李宏毅-食物图像分类器
李宏毅-食物图像分类器
1 实验目的
掌握使用Pytorch的使用方法:
- Pytorch的安装以及环境搭建
- Pytorch处理数据
- Pytorch计算梯度以及搭建神经网络
- Pytorch训练模型
并使用Pytorch来训练CNN模型,实作一个食物的图像分类器。
2 实验要求
- 可以使用tensorflow或者pytorch库
- 必须使用CNN实作model
- 不能使用额外dataset
- 禁止使用 pre-trained model(只能自己手写CNN)
- 请不要上网寻找 label
- 上传格式为 csv,第一行必须为 Id, Category,第二行开始为预测结果,
每行分别为 id 以及预测的 Category,请以逗号分隔 - 请说明你实现的CNN模型,其模型架构、训练参数量和准确率为何
- 请实作与第一题接近的参数量,但CNN深度(CNN层数)减半的模型,并说明其模型架构、训练参数量和准确率为何
- 请说明由 1 ~ 2 题的实验中你观察到了什么
- 请尝试 data normalization 及 data augmentation,说明实作方法并且说明实行前后对准确率有什么样的影响
3 实验环境
3.1 硬件环境
- 笔记本电脑
- Intel Core i5
- NVIDIA GeForce MX350
3.2 软件环境
- windows10操作系统
- Python 3.8 64-bit
- Visual Studio Code
- NVIDIA CUDA
- Kaggle Accelerator GPU
4 实验数据
此次数据集为网络上搜集到的食物照片,共有11类:
Bread, Dairy product, Dessert, Egg, Fried food, Meat, Noodles/Pasta, Rice, Seafood, Soup, Vegetable/Fruit
Training set: 9866张
Validation set: 3430张
Testing set: 3347张
下载 zip 文件后解压缩会有三个文件夹,分别为training、validation 以及 testing
training 以及 validation 中的照片名称格式为 [类别]_[编号].jpg,例如 3_100.jpg 即为类别 3 的照片(编号不重要)
5 模型A:5Layers
5.1 读取数据集
首先定义函数readfile,输入参数path为文件夹路径名,布尔型参数label判断是否需要额外读取label。
readfile函数先通过os.listdir()返回文件夹包含的文件或文件夹的名字的列表,再利用OpenCV(cv2)读入图片,将每个图片的形状统一缩放为128*128,最后存放在numpy array中返回:
def readfile(path, label):image_dir = sorted(os.listdir(path))# 创建array类型的x为输入向量# 一共len(image_dir)个图片,每个图片像素大小128*128,分为3个channel# 所以向量大小为len(image_dir)*128*128*3# 其次规定了数据类型为uint8x = np.zeros((len(image_dir), 128, 128, 3), dtype=np.uint8)# 创建array类型的y为输出向量# 一共len(image_dir)个图片,每个图片各有1个label# 所以向量大小为len(image_dir)*1# 同样规定了数据类型为uint8y = np.zeros((len(image_dir)), dtype=np.uint8)# 枚举每个图片的路径for i, file in enumerate(image_dir):# 拼接图片路径并读取图片数据img = cv2.imread(os.path.join(path, file))# 将每个图片统一resize为128*128x[i, :, :] = cv2.resize(img,(128, 128))# 是否有label即输出,有则将其存入y向量if label:y[i] = int(file.split("_")[0])# 根据label是否为True返回值不同if label:return x, yelse:return x
找到数据集的目录路径,利用刚刚定义的readfile函数读取数据集,并计算输出训练集和验证集的大小:
# 所有数据集的目录路径
workspace_dir = '../input/ml-lab/food11'
print("Reading data......")
# 用自定义的readfile函数读取训练集数据,label已知,所以参数为True
train_x, train_y = readfile(os.path.join(workspace_dir, "training"), True)
# 训练集大小
print("Size of training data = {}".format(len(train_x)))
# 用自定义的readfile函数读取验证集数据,label已知,所以参数为True
val_x, val_y = readfile(os.path.join(workspace_dir, "validation"), True)
# 验证集大小
print("Size of validation data = {}".format(len(val_x)))
# 用自定义的readfile函数读取测试集数据,label未知,所以参数为False
test_x = readfile(os.path.join(workspace_dir, "test"), False)
# 测试集大小
print("Size of Testing data = {}".format(len(test_x)))
5.2 数据预处理
定义训练集和验证集的数据处理对象transforms.Compose(),transforms.Compose()是一个图像预处理包,它可以包含其类内的一系列操作:
- transforms.Resize()把给定的图片resize到given size
- transforms.ToPILImage()将tensor转换为PIL图像
- transforms.ToTensor()将PIL图像转换为tensor
这里将训练集和验证集的数据处理分开定义是为了便于之后模型的改进:
train_transform = transforms.Compose([# 转换为PIL图像transforms.ToPILImage(),# 转换为Tensor对象transforms.ToTensor(),
])
test_transform = transforms.Compose([# 转换为PIL图像transforms.ToPILImage(),# 转换为Tensor对象transforms.ToTensor(),
])
自定义一个类ImgDataset来继承Dataset,然后实现getitem()方法和len()方法,len()返回Dataset的大小,getitem()返回某个规定index图片处理后的结果:
class ImgDataset(Dataset):# 魔术构造函数初始化def __init__(self, x, y=None, transform=None):# 承接向量x和yself.x = xself.y = y# 将label的类型转为LongTensorif y is not None:self.y = torch.LongTensor(y)# 使用刚刚定义的transformself.transform = transformdef __len__(self):return len(self.x)def __getitem__(self, index):X = self.x[index]if self.transform is not None:# 图片处理X = self.transform(X)if self.y is not None:# 获取labelY = self.y[index]return X, Yelse:return X
定义数据处理的块大小,再对训练集和验证集实例化刚刚定义的Dataset类:
batch_size = 128
train_set = ImgDataset(train_x, train_y, train_transform)
val_set = ImgDataset(val_x, val_y, test_transform)
Dataloader的处理逻辑是先通过Dataset类里面的 getitem()函数获取单个的数据,然后组合成batch,再使用collate_fn所指定的函数对这个batch做一些操作,比如padding等。
另外Dataloader的布尔类型参数shuffle决定是否打乱数据,训练集需要,验证集不需要:
train_loader = DataLoader(train_set, batch_size=batch_size, shuffle=True)
val_loader = DataLoader(val_set, batch_size=batch_size, shuffle=False)
5.3 神经网络架构
5.3.1 CNN神经网络
在使用torch.nn.Sequential构建CNN神经网络过程中使用了pytorch库中nn模块的四个函数,分别为:
- 卷积运算函数torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
- 归一化处理函数torch.nn.BatchNorm2d(channels)可以使得在过激活函数的时候不会因为数据过大导致网络的不稳定
- 激活函数torch.nn.ReLU()
- 池化函数torch.nn.MaxPool2d(kernel_size, stride, padding)采用MaxPooling策略,可以降低模型的运算量
第一层:
卷积层3个channel,64个filter,每个filter大小3*3,stride=1,padding=1,输入3*128*128,输出64*128*128。
池化层使用Max Pooling方法,输入64*128*128,输出64*64*64。
nn.Conv2d(3, 64, 3, 1, 1),
nn.BatchNorm2d(64),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
第二层:
卷积层64个channel,128个filter,每个filter大小3*3,stride=1,padding=1,输入64*64*64,输出128*64*64。
池化层使用Max Pooling方法,输128*64*64,输出128*32*32。
nn.Conv2d(64, 128, 3, 1, 1),
nn.BatchNorm2d(128),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
第三层:
卷积层,128个channel,256个filter,每个filter大小3*3,stride=1,padding=1,输入128*32*32,输出256*32*32。
池化层使用Max Pooling方法,输入256*32*32,输出256*16*16。
nn.Conv2d(128, 256, 3, 1, 1),
nn.BatchNorm2d(256),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
第四层:
卷积层,256个channel,512个filter,每个filter大小3*3,stride=1,padding=1,输入256*16*16,输出512*16*16。
池化层使用Max Pooling方法,输入512*16*16,输出512*8*8。
nn.Conv2d(256, 512, 3, 1, 1),
nn.BatchNorm2d(512),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
第五层:
卷积层,512个channel,512个filter,每个filter大小3*3,stride=1,padding=1,输入512*8*8,输出512*8*8。
池化层使用Max Pooling方法,输入512*8*8,输出512*4*4。
nn.Conv2d(512, 512, 3, 1, 1),
nn.BatchNorm2d(512),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
5.3.2 全连接神经网络
在使用torch.nn.Sequential构建全连接神经网络过程中使用了pytorch库中nn模块的两个函数,分别为:
- 全连接分类器torch.nn.Linear(in_features , out_features)
- 激活函数torch.nn.ReLU()
self.fc = nn.Sequential(# 输入512*4*4,输出1024*1nn.Linear(512*4*4, 1024),nn.ReLU(),# 输入1024*1,输出512*1nn.Linear(1024, 512),nn.ReLU(),# 输入512*1,输出11*1,即11种食物种类nn.Linear(512, 11)
)
5.3.3 计算参数量
输入 | filter | 输出 | 计算式 | 参数量 | |
---|---|---|---|---|---|
CNN1 | 3*(128*128) | 64*(3*3) | 64*(128*128) | 64*(3*3*3) | 1728 |
CNN2 | 64*(64*64) | 128*(3*3) | 128*(64*64) | 128*(3*3*64) | 73728 |
CNN3 | 128*(32*32) | 256*(3*3) | 256*(32*32) | 256*(3*3*128) | 294912 |
CNN4 | 256*(16*16) | 512*(3*3) | 512*(16*16) | 512*(3*3*256) | 1179648 |
CNN5 | 512*(8*8) | 512*(3*3) | 512*(8*8) | 512*(3*3*512) | 2359296 |
FC1 | 512*4*4 | 1024 | (8192+1)*1024 | 8389632 | |
FC2 | 1024 | 512 | (1024+1)*512 | 524800 | |
FC3 | 512 | 11 | (512+1)*11 | 5643 |
参数总量=1728+73728+294912+1179648+2359296+8389632+524800+5643=12829387
5.4 训练和验证
首先实例化刚刚定义的训练模型,并初始化一些参数,如GPU加速、损失函数、学习率、迭代次数等:
# GPU加速
model = Classifier().cuda()
# 由于是分类模型,损失函数使用交叉熵
loss = nn.CrossEntropyLoss()
# optimizer使用Adam优化器,学习率设为0.001
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 迭代次数
num_epoch = 30
每次迭代的过程如下:
训练过程包括切换model为train,通过模型输出预测值,计算某个batch的损失函数和梯度,利用梯度更新参数值,最后汇总得到这一轮迭代的准确率和loss。
验证过程也类似,切换model为eval确保在验证的过程是使用的训练数据的参数,直接通过模型输出预测值与实际label比较计算得到准确率和loss即可。
for epoch in range(num_epoch):# 记录开始时间epoch_start_time = time.time()# 训练集上的准确率train_acc = 0.0# 训练集上的losstrain_loss = 0.0# 验证集上的准确率val_acc = 0.0# 验证集上的lossval_loss = 0.0# 确保model是在train model,即训练model.train() for i, data in enumerate(train_loader):# 梯度参数归零optimizer.zero_grad()# 呼叫forward函数,并得到预测值train_pred = model(data[0].cuda())# 计算这个batch的lossbatch_loss = loss(train_pred, data[1].cuda())# 计算每个参数的梯度batch_loss.backward()# 更新参数值optimizer.step() # 更新准确率,numpy.argmax(array, axis)返回一个numpy数组中最大值的索引值train_acc += np.sum(np.argmax(train_pred.cpu().data.numpy(), axis=1) == data[1].numpy())# 将这个batch的loss添加到总losstrain_loss += batch_loss.item()# 切换model到eval model,即测试model.eval()with torch.no_grad():for i, data in enumerate(val_loader):# 呼叫forward函数,并得到预测值val_pred = model(data[0].cuda())# 计算这个batch的lossbatch_loss = loss(val_pred, data[1].cuda())# 更新准确率,numpy.argmax(array, axis)返回一个numpy数组中最大值的索引值val_acc += np.sum(np.argmax(val_pred.cpu().data.numpy(), axis=1) == data[1].numpy())# 将这个batch的loss添加到总lossval_loss += batch_loss.item()#打印本次迭代的结果print('[%03d/%03d] %2.2f sec(s) Train Acc: %3.6f Loss: %3.6f | Val Acc: %3.6f loss: %3.6f' % (epoch + 1, num_epoch, time.time()-epoch_start_time, train_acc/train_set.__len__(), train_loss/train_set.__len__(), val_acc/val_set.__len__(), val_loss/val_set.__len__()))
5.5 扩大训练集
在5.4中我们已经通过训练找到了比较好的参数,并通过验证集大概得到了模型的准确率。
我们还想进一步训练模型,但是限于实验要求不能使用数据集之外的数据。
一个很好的策略就是扩大训练集,利用的就是5.4中的验证集,将训练集和验证集合并为新的更大的训练集,在这个新的训练集上再次训练,这样充分利用了实验给出的数据集。
下面的代码展示了如何将训练集和验证集合并为新的更大的训练集:
# 拼接训练集和验证集成为一个新的更大的训练集
train_val_x = np.concatenate((train_x, val_x), axis=0)
train_val_y = np.concatenate((train_y, val_y), axis=0)
# 对新的训练集实例化Dataset
train_val_set = ImgDataset(train_val_x, train_val_y, train_transform)
# 对新的训练集进行DataLoader,其中布尔类型参数shuffle决定是否打乱数据,训练集需要,所以为True
train_val_loader = DataLoader(train_val_set, batch_size=batch_size, shuffle=True)
训练过程同5.4中的训练过程,此时已经没有验证集,所以没有验证过程,代码几乎相同,限于篇幅这里就不赘述了。
5.6 预测结果
先载入测试集到Dataset中,切换模型的model为eval确保在预测的过程是使用的训练数据的参数,另外定义列表prediction用于存储预测结果:
# 对测试集实例化Dataset
test_set = ImgDataset(test_x, transform=test_transform)
# 对测试集进行DataLoader,其中布尔类型参数shuffle决定是否打乱数据,测试集不需要,所以为False
test_loader = DataLoader(test_set, batch_size=batch_size, shuffle=False)
# 切换model到eval model,即测试
model_best.eval()
# 存储预测值,以便于写入结果文件
prediction = []
预测过程类似验证过程,将输入给到训练好的模型,得到输出结果并添加到结果列表prediction:
with torch.no_grad():for i, data in enumerate(test_loader):# 呼叫forward函数,并得到预测值test_pred = model_best(data.cuda())# 得到该图片的预测结果,通过numpy.argmax(array, axis)返回一个numpy数组中最大值的索引值test_label = np.argmax(test_pred.cpu().data.numpy(), axis=1)#将结果加入预测结果的列表for y in test_label:prediction.append(y)
最终按照实验要求整理格式,并输出结果到csv文件
with open("predict_模型A_5Layers.csv", 'w') as f:f.write('Id,Category\n')for i, y in enumerate(prediction):f.write('{},{}\n'.format(i, y))
5.7 模型准确率
训练次数 | 训练集准确率 | 验证集准确率 | 扩大训练集准确率 |
---|---|---|---|
10 | 0.647172 | 0.472595 | 0.706453 |
20 | 0.861545 | 0.581050 | 0.942464 |
30 | 0.979830 | 0.638776 | 0.980445 |
6 模型B:3Layers
6.1 深度减半的CNN神经网络
为了达到与模型A相近的参数量,不可以单纯从5层CNN中随意删除2层来达到目的,需要适当调整filter的数量。
第一层:
卷积层3个channel,256个filter,每个filter大小3*3,stride=1,padding=1,输入3*128*128,输出256*128*128。
池化层使用Max Pooling方法,输入256*128*128,输出256*64*64。
nn.Conv2d(3, 256, 3, 1, 1),
nn.BatchNorm2d(256),
nn.ReLU(),
nn.MaxPool2d(2, 2, 0),
第二层:
卷积层256个channel,512个filter,每个filter大小3*3,stride=1,padding=1,输入256*64*64,输出512*64*64。
池化层使用Max Pooling方法,输入512*64*64,输出512*16*16。
nn.Conv2d(256, 512, 3, 1, 1),
nn.BatchNorm2d(512),
nn.ReLU(),
nn.MaxPool2d(4, 4, 0),
第三层:
卷积层,512个channel,512个filter,每个filter大小3*3,stride=1,padding=1,输入512*16*16,输出512*16*16。
池化层使用Max Pooling方法,输入512*16*16,输出512*4*4。
nn.Conv2d(512, 512, 3, 1, 1),
nn.BatchNorm2d(512),
nn.ReLU(),
nn.MaxPool2d(4, 4, 0),
6.2 计算参数量
输入 | filter | 输出 | 计算式 | 参数量 | |
---|---|---|---|---|---|
CNN1 | 3*(128*128) | 256*(3*3) | 256*(128*128) | 256*(3*3*3) | 6912 |
CNN2 | 256*(64*64) | 512*(3*3) | 512*(64*64) | 512*(3*3*256) | 1179648 |
CNN3 | 512*(16*16) | 512*(3*3) | 512*(16*16) | 512*(3*3*512) | 2359296 |
FC1 | 512*4*4 | 1024 | (8192+1)*1024 | 8389632 | |
FC2 | 1024 | 512 | (1024+1)*512 | 524800 | |
FC3 | 512 | 11 | (512+1)*11 | 5643 |
参数总量=6912+1179648+2359296+8389632+524800+5643=12465931
可见参数总量和模型A的参数总量(12829387)相近,可以更客观地反映出CNN深度对于模型准确率的影响。
6.3 模型准确率
训练次数 | 训练集准确率 | 验证集准确率 | 扩大训练集准确率 |
---|---|---|---|
10 | 0.697243 | 0.515160 | 0.742329 |
20 | 0.865599 | 0.586006 | 0.922307 |
30 | 0.977194 | 0.634402 | 0.973827 |
7 模型C:5Layers+normalization
7.1 归一化过程
transforms.Normalize()用均值和标准差归一化张量图像,将每个元素分布到(-1,1),参照如下公式:
σ = 1 N ∑ i = 1 N ( x i − μ ) 2 z i = x i − μ σ \sigma=\sqrt{\frac{1}{\mathrm{~N}} \sum_{i=1}^{\mathrm{N}}\left(\mathrm{x}_{\mathrm{i}}-\mu\right)^{2}}\\ \mathrm{z}_{\mathrm{i}}=\frac{\mathrm{x}_{\mathrm{i}}-\mu}{\sigma} σ= N1i=1∑N(xi−μ)2 zi=σxi−μ
修改训练集和验证集的数据处理对象transforms.Compose():
train_transform = transforms.Compose([# 转换为PIL图像transforms.ToPILImage(),# 转换为Tensor对象transforms.ToTensor(), # 用均值和标准差归一化张量图像transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])
test_transform = transforms.Compose([# 转换为PIL图像transforms.ToPILImage(),# 转换为Tensor对象transforms.ToTensor(), # 用均值和标准差归一化张量图像transforms.Normalize((0.5,0.5,0.5),(0.5,0.5,0.5))
])
7.2 模型准确率
训练次数 | 训练集准确率 | 验证集准确率 | 扩大训练集准确率 |
---|---|---|---|
10 | 0.632779 | 0.477259 | 0.727888 |
20 | 0.840462 | 0.625656 | 0.947879 |
30 | 0.988242 | 0.650437 | 0.980295 |
8 模型D:5Layers+augmentation
8.1 数据增强过程
数据增强包括翻转(flips)、移位(translations)、旋转(rotations)、缩放比例(Scale)、裁剪(Crop)、高斯噪声(Gaussian Noise)等微小的改变,以此训练出的模型适应性会更强。
在图像预处理包transforms.Compose()中可以找到相应的函数来完成这些操作:
- transforms.RandomHorizontalFlip()以0.5的概率水平翻转给定的PIL图像
- transforms.RandomVerticalFlip()以0.5的概率竖直翻转给定的PIL图像
- transforms.RandomGrayscale()将图像以一定的概率转换为灰度图像
- transforms.ColorJitter()随机改变图像的亮度对比度和饱和度
- transforms.RandomResizedCrop()将PIL图像裁剪成任意大小和纵横比
- transforms.RandomRotation()按照degree将图像随机旋转一定角度
由于测试集不需要数据增强,因此只需要修改训练集的数据处理对象transforms.Compose():
# 训练集相比测试集额外添加了数据增强(data augmentation)
train_transform = transforms.Compose([# 转换为PIL图像transforms.ToPILImage(),# 以0.5概率水平翻转随机PIL图像transforms.RandomHorizontalFlip(),# 按照degree将图像随机旋转一定角度transforms.RandomRotation(15), # 转换为Tensor对象transforms.ToTensor(),
])
8.2 模型准确率
训练次数 | 训练集准确率 | 验证集准确率 | 扩大训练集准确率 |
---|---|---|---|
10 | 0.587168 | 0.531778 | 0.660725 |
20 | 0.757247 | 0.614577 | 0.809792 |
30 | 0.850091 | 0.661516 | 0.912229 |
9 分析评估
9.1 CNN深度对模型准确率的影响
根据5.7和6.3中的数据,模型B无论是在训练集还是验证集上的准确率相比模型A均有轻微下降,且模型B在训练过程中的收敛速度稍快。
分析原因,模型A的参数总量为12829387,而模型B的参数总量为12465931,参数在数量上接近,后者相比前者略少,CNN层数也仅差2层,非线性的表达能力差别不是特别大。
在一定范围内,CNN的深度越深,参数量越多,模型的训练效果就会越好。
但是目前研究已经发现发现传统的CNN网络结构随着层数加深到一定程度之后,越深的CNN网络训练出的模型反而效果更差。
9.2 归一化对模型准确率的影响
根据5.7和7.2中的数据,经过data normalization之后,模型C无论是在训练集还是验证集上的准确率相比模型A均有提升,其中在验证集上的准确率提升了2个百分点,可见归一化操作对模型性能提升方面发挥了积极作用。
由于模型A和模型C的神经网络架构相同,均为5Layers,所以两个模型在训练过程中的收敛速度接近。
9.3 数据增强对模型准确率的影响
根据5.7和8.2中的数据,经过data augmentation之后,模型D虽然在训练集上的准确率相比模型A有所降低,但是在验证集上的准确率有了比模型C更大的提升,可以认为data augmentation增强了模型的适应性,提升了模型的性能。
由于模型A和模型D的神经网络架构相同,均为5Layers,所以两个模型在训练过程中的收敛速度接近。
9.4 进一步优化模型
如果想要进一步优化模型,还可以从以下几个并未在实验中探究的方面入手:
- 尝试寻找filter的最佳kernel size
- 尝试寻找最佳的learning rate
- 尝试寻找最佳的batch size
- 进一步完善模型的神经网络结构
- 进一步对数据集data augmentation
10 References
[1] python.org
[2] kaggle.com
[3] baike.baidu.com
[4] www.csdn.net
[5] pytorch.org
【机器学习】李宏毅-食物图像分类器相关推荐
- 使用 Fastai 构建食物图像分类器
背景 社交媒体平台是分享有趣的图像的常用方式.食物图像,尤其是与不同的美食和文化相关的图像,是一个似乎经常流行的话题.Instagram 等社交媒体平台拥有大量属于不同类别的图像.我们都可能使用谷歌图 ...
- 词袋模型 matlab,【火炉炼AI】机器学习051-视觉词袋模型+极端随机森林建立图像分类器...
[火炉炼AI]机器学习051-视觉词袋模型+极端随机森林建立图像分类器 (本文所使用的Python库和版本号: Python 3.6, Numpy 1.14, scikit-learn 0.19, m ...
- 30分钟 Keras 创建一个图像分类器
深度学习是使用人工神经网络进行机器学习的一个子集,目前已经被证明在图像分类方面非常强大.尽管这些算法的内部工作在数学上是严格的,但 Python 库(比如 keras)使这些问题对我们所有人都可以接近 ...
- 麻省理工研究:深度图像分类器,居然还会过度解读
作者 | 青苹果 来源 | 数据实战派 某些情况下,深度学习方法能识别出一些在人类看来毫无意义的图像,而这些图像恰恰也是医疗和自动驾驶决策的潜在隐患所在.换句话说,深度图像分类器可以使用图像的边界,而 ...
- tensorflow 迁移学习_基于 TensorFlow.js 1.5 的迁移学习图像分类器
在黑胡桃社区的体验案例中,有一个"人工智能教练",它其实是一个自定义的图像分类器.使用 TensorFlow.js 这个强大而灵活的 Javascript 机器学习库可以很轻松地构 ...
- 用PyTorch创建一个图像分类器?So easy!(Part 1)
经过了几个月的学习和实践,我完成了优达学城网站上<Python Programming with Python Nanodegree>课程的学习,该课程的终极项目就是使用Pytorch为1 ...
- 首期「线上开发」直播出炉!轻量算法+轻量开发:AI 小白也能上手实操的一款图像分类器...
几行代码,零基础AI小白也能上手开发图像分类器.5 月 16 日,早 9:30 直播等你,带你线上完成基于 TF2.2 的宠物分类器. 进入 AI 时代,想成为一名 AI 开发者却不是一件那么容易的事 ...
- 如何用PyTorch训练图像分类器
本文为 AI 研习社编译的技术博客,原标题 : How to Train an Image Classifier in PyTorch and use it to Perform Basic Infe ...
- 如何使用 Google 的 AutoAugment 改进图像分类器
本文为 AI 研习社编译的技术博客,原标题 : How to improve your image classifier with Google's AutoAugment 作者 | Philip P ...
最新文章
- CrazyWing:Python自动化运维开发实战 六、流程控制
- [IOI2008]Island
- echarts散点图使用
- 进入51cto之后的发展方向
- 阿里巴巴对Java编程【异常处理】的规约
- Java XMPP负载测试工具
- 连亏172亿,割肉卖楼,年收3700亿、闻名全球的巨头,败退中国!
- Redis 面试一定要知道的 3 个 问题!
- 酷客多小程序DIY体系全面升级,还加入了这些新功能
- 如何将汇编语言转换为c语言,如何把汇编语言转换成C语言
- Qt_屏幕保护程序、进程监听、数据库读取、屏幕保护
- windows切屏快捷键
- 系统同步网络时间服务器不可用,电脑时间同步出错 RPC服务器不可用解决方案...
- 机器学习项目实战——集成预测政治献金
- 2021-07-23 N卡显示器亮度设置
- 面试官:SPA(单页应用)首屏加载速度慢怎么解决?
- 利用HTML5新特性实现拖拽交换表格单元格元素
- excel通过合并单元格“增加行高”(大于最大行高409)
- MMA7361三轴加速度模块使用注意的问题
- win10共享打印机怎么设置_关于win10网络共享,选择“启用文件和打印机共享”之后,无法保存设置的解决办法...
热门文章
- 基于多层结构的网络游戏平台的研究与应用
- kaggle TMDB Box Office Prediction
- NOIP大纲整理:(零)历年2000-2016NOIP提高组题目分析
- 快来体验一下,让你的浏览器焕然一新
- 2022-4-28作业
- IllegalStateException: Couldn‘t read row 0, col 10 from CursorWindow. Make sure the Cursor is initi
- 如何用c语言给信息加密,求助:如何用C语言实现LFSR加密
- oracle20c最新版本,Oracle DUL支持Oracle 20c
- 陈艾盐:春燕百集访谈节目第二十五集
- 如何修改Bash Shell的提示符的格式和配色