AI on Mac Studio – 1: Running fuyu-8B on mac studio

This is the first article about running an AI model on Mac Studio, and I will continue to migrate the environment from CUDA / Nvidia GPU to Mac MPS.

Why did I choose Mac Studio?

I chose Mac Studio because it is less expensive. It has 192GB of memory that can be used as a GPU. This means that it is possible to migrate the program from Nvidia GPU and save some money for personal use.

What is Fuyu-8B?

We are releasing Fuyu-8B, a small version of the multimodal model that powers our product. The model is available on HuggingFace. We think Fuyu-8B is exciting because:

  1. It has a much simpler architecture and training procedure than other multimodal models, making it easier to understand, scale, and deploy.
  2. It is designed from the ground up for digital agents, so it can support arbitrary image resolutions, answer questions about graphs and diagrams, answer UI-based questions, and perform fine-grained localization on screen images.
  3. It is fast – we can get responses for large images in less than 100 milliseconds.
  4. Despite being optimized for our use case, it performs well at standard image understanding benchmarks such as visual question-answering and natural-image-captioning.

Ok, let’s do it now.

Prepare the environment:

  1. You need Python 3.6+ and virtualenv installed. Conda or venv also work.

cssCopy code

virtualenv -p python3 py3

  1. Download the HuggingFace transformers and clone the transformer from GitHub.

bashCopy code

git clone https://github.com/huggingface/transformers.git cd transformers pip install .

  1. Download the model from https://huggingface.co/adept/fuyu-8b. You can use clone or download it manually, depending on your network speed.
  2. Install PyTorch from this page https://pytorch.org/get-started/locally/ depending on your environment. Since I am using Mac M2 Studio, I should install this:

Copy code

pip3 install torch torchvision torchaudio

  1. You are almost done here; now we can start the samples.

Sample 1:

from transformers import FuyuProcessor, FuyuForCausalLM
from PIL import Image
# load model and processor
model_id = "."
processor = FuyuProcessor.from_pretrained(model_id)
model = FuyuForCausalLM.from_pretrained(model_id, device_map="mps", torch_dtype=torch.float16)
# prepare inputs for the model
text_prompt = "Generate a coco-style caption.\n"
image_path = "bus.png"  # https://huggingface.co/adept-hf-collab/fuyu-8b/blob/main/bus.png
image = Image.open(image_path)
inputs = processor(text=text_prompt, images=image, return_tensors="pt")
for k, v in inputs.items():
    inputs[k] = v.to("mps")
# autoregressively generate text
generation_output = model.generate(**inputs, max_new_tokens=7)
generation_text = processor.batch_decode(generation_output[:, -7:], skip_special_tokens=True)
print(generation_text)

Sample 2:

import os
from transformers import FuyuProcessor, FuyuForCausalLM
from PIL import Image
import torch
def list_files_in_directory(path, extensions=[".png", ".jpeg", ".jpg", ".JPG", ".PNG", ".JPEG"]):
    files = [f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) and any(f.endswith(ext) for ext in extensions)]
    return files
def main():
    # load model and processor
    model_id = "." #adept/fuyu-8b"
    processor = FuyuProcessor.from_pretrained(model_id)
    model = FuyuForCausalLM.from_pretrained(model_id, device_map="mps", torch_dtype=torch.float16) # To solve OOM, float16 enables operation with only 24GB of VRAM. Alternatively float16 can be replaced with bfloat16 with differences in loading time and inference time.
    # Load last image path or ask user
    try:
        with open("last_path.txt", "r") as f:
            last_path = f.read().strip()
        user_input = input(f"Do you want to use the last path '{last_path}'? (yes/no, default yes): ")
        if not user_input or user_input.lower() != 'no':
            last_path = last_path
        else:
            raise ValueError("User chose to input a new path.")
    except:
        last_path = input("Please provide the image directory path: ")
        with open("last_path.txt", "w") as f:
            f.write(last_path)
    while True:
        # List the first 10 images in the directory
        images = list_files_in_directory(last_path)[:10]
        for idx, image in enumerate(images, start=1):
            print(f"{idx}. {image}")
        # Allow the user to select an image
        image_choice = input(f"Choose an image (1-{len(images)}) or enter its name: ")
        try:
            idx = int(image_choice)
            image_path = os.path.join(last_path, images[idx-1])
        except ValueError:
            image_path = os.path.join(last_path, image_choice)
        try:
            image = Image.open(image_path)
        except:
            print("Cannot open the image. Please check the path and try again.")
            continue
        questions = [
            "Generate a coco-style caption.",
            "What color is the object?",
            "Describe the scene.",
            "Describe the facial expression of the character.",
            "Tell me about the story from the image.",
            "Enter your own question"
        ]
        # Asking the user to select a question from list, or select to input one
        for idx, q in enumerate(questions, start=1):
            print(f"{idx}. {q}")
        q_choice = int(input("Choose a question or enter your own: "))
        if q_choice <= 5:
            text_prompt = questions[q_choice-1] + '\n'
        else:
            text_prompt = input("Please enter your question: ") + '\n'
        while True: # To enable the user to ask further question about an image
            inputs = processor(text=text_prompt, images=image, return_tensors="pt")
            for k, v in inputs.items():
                inputs[k] = v.to("mps")
            # To eliminate attention_mask warning
            inputs["attention_mask"] = torch.ones(inputs["input_ids"].shape, device="mps")
            generation_output = model.generate(**inputs, max_new_tokens=50, pad_token_id=model.config.eos_token_id)
            generation_text = processor.batch_decode(generation_output[:, -50:], skip_special_tokens=True)
            print("Answer:", generation_text[0])
            text_prompt = input("Ask another question about the same image or type '/exit' to exit: ") + '\n'
            if text_prompt.strip() == '/exit':
                break
#if name == "main":
main()

yes, It is Chinese. But not the Chinese fuyu-7b knows. It is not “食” (eating) , but “我不想洗碗”( i don’t want to wash the dishes). Fuyu-7b is lying. lol.

redsocks升级记录

一直在用redsocks做流量转发,用着还是挺不错的,但是偶尔还是会hang住,导致网络卡住。老早就有升级的想法,一直没有动手。

什么是redsocks?

This tool allows you to redirect any TCP connection to SOCKS or HTTPS proxy using your firewall, so redirection may be system-wide or network-wide.

When is redsocks useful?

  • you want to route part of TCP traffic via OpenSSH DynamicForward Socks5 port using firewall policies. That was original redsocks development goal;
  • you use DVB ISP and this ISP provides internet connectivity with some special daemon that may be also called “Internet accelerator” and the accelerator acts as a proxy and has no “transparent proxy” feature and you need it. Globax was an example of alike accelerator, but Globax 5 has transparent proxy feature. That was the second redsocks` development goal;
  • you have to pass traffic through proxy due to corporate network limitation. That was never a goal for redsocks, but users have reported success with some proxy configurations.

以上是官方介绍。功能确实很强大,毕竟是俄国大佬的作品,继承了俄国产品强大而又粗糙的刻板印象。翻了他的repo,发现最后更新是2019年,而且还是改typo,其他的issue没有回复,大概大佬也不打算维护了吧。找了好久替代,发现了它的一个fork,似乎改了不少东西,就拖下来试试看吧。运行了一晚上,稳定性似乎还不错。

github地址 https://github.com/semigodking/redsocks

该repo依赖openssl和libevent2,libevent2在树莓派的repo中没有了,所以只能现编译。

现在把安装过程记录一下(仅限Raspberry Pi):

#安装openssl开发包

sudo apt install libssl-dev

#获取代码

wget https://github.com/libevent/libevent/releases/download/release-2.1.12-stable/libevent-2.1.12-stable.tar.gz

tar xvfz libevent-2.1.12-stable.tar.gz

cd libevent-2.1.12-stable

编译、安装

make
sudo make install

#克隆redsocks2的代码

git clone https://github.com/semigodking/redsocks

cd redsocks

make DISABLE_SHADOWSOCKS=1 ENABLE_STATIC=1

编译完,修改之前redsocks的配置文件、替换redsocks文件,重启服务即可。

目前暂时稳定。

訓練diffusion模型

訓練擴散模型


無條件圖像生成是擴散模型的一種流行應用,它生成的圖像與用於訓練的數據集中的圖像相似。通常,最好的結果是通過在特定數據集上微調預訓練模型來獲得的。您可以在 Hub 上找到許多這樣的檢查點,但如果您找不到您喜歡的檢查點,您可以隨時訓練自己的檢查點!

本教程將教您如何在 Smithsonian Butterflies 數據集的子集上從頭開始訓練 UNet2DModel,以生成您自己的 🦋 蝴蝶 🦋。

💡 本培訓教程基於 🧨 擴散器筆記本進行培訓。有關擴散模型的更多詳細信息和背景(例如它們的工作原理),請查看筆記本!

在開始之前,請確保您安裝了🤗數據集來加載和預處理圖像數據集,並安裝了🤗加速,以簡化在任意數量的 GPU 上的訓練。以下命令還將安裝 TensorBoard 以可視化訓練指標(您還可以使用權重和偏差來跟踪您的訓練)。

我們鼓勵您與社區分享您的模型,為此,您需要登錄您的 Hugging Face 帳戶(如果您還沒有帳戶,請在此處創建一個!)。您可以從筆記本登錄並在出現提示時輸入您的令牌:

Copied>>> from huggingface_hub import notebook_login >>> notebook_login()

或者從終端登錄:

Copiedhuggingface-cli login

由於模型檢查點非常大,因此安裝 Git-LFS 來對這些大文件進行版本控制:

Copied!sudo apt -qq install git-lfs !git config –global credential.helper store

訓練配置

為了方便起見,創建一個包含訓練超參數的 TrainingConfig 類(隨意調整它們):

Copied>>> from dataclasses import dataclass >>> @dataclass … class TrainingConfig: … image_size = 128 # the generated image resolution … train_batch_size = 16 … eval_batch_size = 16 # how many images to sample during evaluation … num_epochs = 50 … gradient_accumulation_steps = 1 … learning_rate = 1e-4 … lr_warmup_steps = 500 … save_image_epochs = 10 … save_model_epochs = 30 … mixed_precision = “fp16” # `no` for float32, `fp16` for automatic mixed precision … output_dir = “ddpm-butterflies-128” # the model name locally and on the HF Hub … push_to_hub = True # whether to upload the saved model to the HF Hub … hub_private_repo = False … overwrite_output_dir = True # overwrite the old model when re-running the notebook … seed = 0 >>> config = TrainingConfig()

加載數據集

您可以使用 🤗 數據集庫輕鬆加載史密森尼蝴蝶數據集:

Copied>>> from datasets import load_dataset >>> config.dataset_name = “huggan/smithsonian_butterflies_subset” >>> dataset = load_dataset(config.dataset_name, split=”train”)

💡 您可以從 HugGan 社區活動中找到其他數據集,也可以通過創建本地 ImageFolder 來使用自己的數據集。如果數據集來自 HugGan 社區活動,則將 config.dataset_name 設置為數據集的存儲庫 ID;如果您使用自己的圖像,則將 imagefolder 設置為。

🤗 Datasets 使用 Image 功能自動解碼圖像數據並將其加載為我們可以可視化的 PIL.Image :

Copied>>> import matplotlib.pyplot as plt >>> fig, axs = plt.subplots(1, 4, figsize=(16, 4)) >>> for i, image in enumerate(dataset[:4][“image”]): … axs[i].imshow(image) … axs[i].set_axis_off() >>> fig.show()

不過,這些圖像的尺寸各不相同,因此您需要先對它們進行預處理:

  • Resize 將圖像大小更改為 config.image_size 中定義的大小。
  • RandomHorizontalFlip 通過隨機鏡像圖像來擴充數據集。
  • Normalize 對於將像素值重新縮放到 [-1, 1] 範圍非常重要,這是模型所期望的。

Copied>>> from torchvision import transforms >>> preprocess = transforms.Compose( … [ … transforms.Resize((config.image_size, config.image_size)), … transforms.RandomHorizontalFlip(), … transforms.ToTensor(), … transforms.Normalize([0.5], [0.5]), … ] … )

使用 🤗 數據集的 set_transform 方法在訓練期間動態應用 preprocess 函數:

Copied>>> def transform(examples): … images = [preprocess(image.convert(“RGB”)) for image in examples[“image”]] … return {“images”: images} >>> dataset.set_transform(transform)

請隨意再次可視化圖像以確認它們已調整大小。現在您已準備好將數據集包裝在 DataLoader 中進行訓練!

Copied>>> import torch >>> train_dataloader = torch.utils.data.DataLoader(dataset, batch_size=config.train_batch_size, shuffle=True)

創建 UNet2D 模型

🧨 Diffusers 中的預訓練模型可以使用您想要的參數輕鬆地從其模型類創建。例如,要創建 UNet2DModel:

Copied>>> from diffusers import UNet2DModel >>> model = UNet2DModel( … sample_size=config.image_size, # the target image resolution … in_channels=3, # the number of input channels, 3 for RGB images … out_channels=3, # the number of output channels … layers_per_block=2, # how many ResNet layers to use per UNet block … block_out_channels=(128, 128, 256, 256, 512, 512), # the number of output channels for each UNet block … down_block_types=( … “DownBlock2D”, # a regular ResNet downsampling block … “DownBlock2D”, … “DownBlock2D”, … “DownBlock2D”, … “AttnDownBlock2D”, # a ResNet downsampling block with spatial self-attention … “DownBlock2D”, … ), … up_block_types=( … “UpBlock2D”, # a regular ResNet upsampling block … “AttnUpBlock2D”, # a ResNet upsampling block with spatial self-attention … “UpBlock2D”, … “UpBlock2D”, … “UpBlock2D”, … “UpBlock2D”, … ), … )

快速檢查樣本圖像形狀與模型輸出形狀是否匹配通常是個好主意:

Copied>>> sample_image = dataset[0][“images”].unsqueeze(0) >>> print(“Input shape:”, sample_image.shape) Input shape: torch.Size([1, 3, 128, 128]) >>> print(“Output shape:”, model(sample_image, timestep=0).sample.shape) Output shape: torch.Size([1, 3, 128, 128])

偉大的!接下來,您需要一個調度程序來向圖像添加一些噪聲。

創建調度程序

根據您使用模型進行訓練還是推理,調度程序的行為會有所不同。在推理過程中,調度器根據噪聲生成圖像。在訓練期間,調度程序從擴散過程中的特定點獲取模型輸出(或樣本),並根據噪聲調度和更新規則將噪聲應用於圖像。

讓我們看一下 DDPMScheduler,並使用 add_noise 方法向之前的 sample_image 添加一些隨機噪聲:

Copied>>> import torch >>> from PIL import Image >>> from diffusers import DDPMScheduler >>> noise_scheduler = DDPMScheduler(num_train_timesteps=1000) >>> noise = torch.randn(sample_image.shape) >>> timesteps = torch.LongTensor([50]) >>> noisy_image = noise_scheduler.add_noise(sample_image, noise, timesteps) >>> Image.fromarray(((noisy_image.permute(0, 2, 3, 1) + 1.0) * 127.5).type(torch.uint8).numpy()[0])

模型的訓練目標是預測添加到圖像中的噪聲。這一步的損失可以通過下式計算:

Copied>>> import torch.nn.functional as F >>> noise_pred = model(noisy_image, timesteps).sample >>> loss = F.mse_loss(noise_pred, noise)

 訓練模型

到目前為止,您已經掌握了開始訓練模型的大部分內容,剩下的就是將所有內容組合在一起。

首先,您需要一個優化器和一個學習率調度器:

Copied>>> from diffusers.optimization import get_cosine_schedule_with_warmup >>> optimizer = torch.optim.AdamW(model.parameters(), lr=config.learning_rate) >>> lr_scheduler = get_cosine_schedule_with_warmup( … optimizer=optimizer, … num_warmup_steps=config.lr_warmup_steps, … num_training_steps=(len(train_dataloader) * config.num_epochs), … )

然後,您需要一種評估模型的方法。為了進行評估,您可以使用 DDPMPipeline 生成一批樣本圖像並將其保存為網格:

Copied>>> from diffusers import DDPMPipeline >>> from diffusers.utils import make_image_grid >>> import math >>> import os >>> def evaluate(config, epoch, pipeline): … # Sample some images from random noise (this is the backward diffusion process).# The default pipeline output type is `List[PIL.Image]` … images = pipeline( … batch_size=config.eval_batch_size, … generator=torch.manual_seed(config.seed), … ).images … # Make a grid out of the images … image_grid = make_image_grid(images, rows=4, cols=4) … # Save the images … test_dir = os.path.join(config.output_dir, “samples”) … os.makedirs(test_dir, exist_ok=True) … image_grid.save(f”{test_dir}/{epoch:04d}.png”)

現在,您可以使用 🤗 Accelerate 將所有這些組件包裝在一個訓練循環中,以輕鬆進行 TensorBoard 日誌記錄、梯度累積和混合精度訓練。要將模型上傳到 Hub,請編寫一個函數來獲取存儲庫名稱和信息,然後將其推送到 Hub。

💡 下面的訓練循環可能看起來令人生畏且漫長,但是當您僅用一行代碼啟動訓練時,這一切都是值得的!如果您迫不及待地想要開始生成圖像,請隨意複製並運行下面的代碼。您可以隨時返回並更仔細地檢查訓練循環,例如當您等待模型完成訓練時。 🤗

Copied>>> from accelerate import Accelerator >>> from huggingface_hub import HfFolder, Repository, whoami >>> from tqdm.auto import tqdm >>> from pathlib import Path >>> import os >>> def get_full_repo_name(model_id: str, organization: str = None, token: str = None): … if token is None: … token = HfFolder.get_token() … if organization is None: … username = whoami(token)[“name”] … return f”{username}/{model_id}” … else: … return f”{organization}/{model_id}” >>> def train_loop(config, model, noise_scheduler, optimizer, train_dataloader, lr_scheduler): … # Initialize accelerator and tensorboard logging … accelerator = Accelerator( … mixed_precision=config.mixed_precision, … gradient_accumulation_steps=config.gradient_accumulation_steps, … log_with=”tensorboard”, … project_dir=os.path.join(config.output_dir, “logs”), … ) … if accelerator.is_main_process: … if config.push_to_hub: … repo_name = get_full_repo_name(Path(config.output_dir).name) … repo = Repository(config.output_dir, clone_from=repo_name) … elif config.output_dir is not None: … os.makedirs(config.output_dir, exist_ok=True) … accelerator.init_trackers(“train_example”) … # Prepare everything# There is no specific order to remember, you just need to unpack the# objects in the same order you gave them to the prepare method. … model, optimizer, train_dataloader, lr_scheduler = accelerator.prepare( … model, optimizer, train_dataloader, lr_scheduler … ) … global_step = 0 … # Now you train the model … for epoch in range(config.num_epochs): … progress_bar = tqdm(total=len(train_dataloader), disable=not accelerator.is_local_main_process) … progress_bar.set_description(f”Epoch {epoch}”) … for step, batch in enumerate(train_dataloader): … clean_images = batch[“images”] … # Sample noise to add to the images … noise = torch.randn(clean_images.shape).to(clean_images.device) … bs = clean_images.shape[0] … # Sample a random timestep for each image … timesteps = torch.randint( … 0, noise_scheduler.config.num_train_timesteps, (bs,), device=clean_images.device … ).long() … # Add noise to the clean images according to the noise magnitude at each timestep# (this is the forward diffusion process) … noisy_images = noise_scheduler.add_noise(clean_images, noise, timesteps) … with accelerator.accumulate(model): … # Predict the noise residual … noise_pred = model(noisy_images, timesteps, return_dict=False)[0] … loss = F.mse_loss(noise_pred, noise) … accelerator.backward(loss) … accelerator.clip_grad_norm_(model.parameters(), 1.0) … optimizer.step() … lr_scheduler.step() … optimizer.zero_grad() … progress_bar.update(1) … logs = {“loss”: loss.detach().item(), “lr”: lr_scheduler.get_last_lr()[0], “step”: global_step} … progress_bar.set_postfix(**logs) … accelerator.log(logs, step=global_step) … global_step += 1 … # After each epoch you optionally sample some demo images with evaluate() and save the model … if accelerator.is_main_process: … pipeline = DDPMPipeline(unet=accelerator.unwrap_model(model), scheduler=noise_scheduler) … if (epoch + 1) % config.save_image_epochs == 0 or epoch == config.num_epochs – 1: … evaluate(config, epoch, pipeline) … if (epoch + 1) % config.save_model_epochs == 0 or epoch == config.num_epochs – 1: … if config.push_to_hub: … repo.push_to_hub(commit_message=f”Epoch {epoch}”, blocking=True) … else: … pipeline.save_pretrained(config.output_dir)

唷,那是相當多的代碼!但您終於準備好使用 🤗 Accelerate 的 notebook_launcher 函數啟動訓練了。向函數傳遞訓練循環、所有訓練參數和進程數(您可以將此值更改為可用的 GPU 數量)以用於訓練:

Copied>>> from accelerate import notebook_launcher >>> args = (config, model, noise_scheduler, optimizer, train_dataloader, lr_scheduler) >>> notebook_launcher(train_loop, args, num_processes=1)

訓練完成後,查看擴散模型生成的最終 🦋 圖像 🦋!

Copied>>> import glob >>> sample_images = sorted(glob.glob(f”{config.output_dir}/samples/*.png”)) >>> Image.open(sample_images[-1])

下一步

無條件圖像生成是可訓練任務的一個示例。您可以訪問🧨 擴散器培訓示例頁面來探索其他任務和培訓技術。以下是您可以學到的一些示例:

  • 文本反轉,一種向模型傳授特定視覺概念並將其集成到生成圖像中的算法。
  • DreamBooth,一種在給定主題的多個輸入圖像的情況下生成主題的個性化圖像的技術。
  • 在您自己的數據集上微調穩定擴散模型的指南。
  • LoRA 使用指南,這是一種內存高效技術,可以更快地微調大型模型。

如何訓練穩定的擴散模型:初學者指南

掌握訓練穩定擴散模型的基礎知識。通過簡單的分步說明,我們將立即將初學者轉變為自信的模型訓練師。一起來學習吧!

近年來,人工智能 (AI) 和機器學習 (ML) 徹底改變了數據分析、預測建模和決策領域。其中一個發展就是穩定擴散模型,它是一種基於歷史數據生成圖像和預測結果的強大工具。

在這份內容廣泛的指南中,我們將深入研究穩定擴散模型的訓練過程,為您提供掌握這一迷人技術必不可少的步驟、最佳實踐和策略。

穩定擴散模型簡介

穩定擴散模型包含一種機器學習算法類型,該算法使用歷史數據來預測特定結果或事件的概率。這些模型採用一種稱為擴散過程的技術,其中包括向輸入圖像添加噪聲,然後隨著時間的推移逐漸減少噪聲以生成最終圖像。此過程產生的圖像比傳統深度學習 (DL) 模型更詳細、更真實。

穩定擴散模型因其處理複雜和抽象文本描述的能力而特別引人注目,這要歸功於一種稱為穩定訓練的新方法。該技術使模型能夠生成與文本輸入一致的高質量圖像,使其比以前的文本到圖像模型有了顯著改進。

穩定擴散模型的數據準備

在訓練穩定擴散模型之前,準備用於訓練模型的數據至關重要。該過程涉及以下步驟:

Data collection 數據採集

收集與您期望的結果相關的準確且最新的數據。確保數據準確地代表您希望模型解決的問題。

Data cleaning 數據清洗

消除數據集中的任何異常值、缺失數據或不一致之處,以最大限度地提高模型的準確性。這可能涉及填充缺失值、糾正錯誤或將數據轉換為更可用的格式。

Data preprocessing 數據預處理

應用各種技術來提高模型的準確性和性能。這可能包括歸一化、標準化或降維。

模型設計和算法選擇

準備好數據後,下一步就是設計穩定擴散模型。這涉及為模型選擇適當的算法、架構和參數。穩定擴散模型中使用的一些流行算法包括:

深度卷積神經網絡(DCNN)

生成對抗網絡(GAN)

變分自動編碼器(VAE)

選擇算法和架構時,請考慮問題的複雜性、數據集的大小以及所需的準確度等因素。

訓練穩定擴散模型

要訓​​練您自己的穩定擴散模型,您可以使用各種工具和平台,例如 Google Colab、Jupyter Notebooks 或 TensorFlow。這些平台提供了用於運行實驗、管理模型和生成圖像的交互式環境。

遵循本節中的步驟將使您能夠創建適合您的需求和偏好的擴散模型,從而產生富有洞察力的預測。以下是訓練穩定擴散模型的步驟:

將準備好的數據集分為訓練集和驗證集。使用訓練集來訓練模型,使用驗證集來評估其性能。

從各種可用選項中選擇合適的穩定擴散模型。

使用 PyTorch 或 TensorFlow 等軟件訓練模型。請注意,根據數據集大小和模型複雜性,訓練持續時間可以從幾個小時到幾天不等。

訓練後,使用驗證集評估模型的性能。

一旦對模型的性能感到滿意,就可以通過向模型提供隨機噪聲向量來生成圖像。

在我們詳細指南的幫助下輕鬆安裝穩定擴散。

模型評估和驗證

訓練穩定擴散模型後,必須評估其性能並驗證其準確性。這可以通過使用各種指標將模型的預測與實際結果進行比較來完成,例如:

均方誤差 (MSE)。

均方根誤差 (RMSE)。

平均絕對誤差 (MAE)。

R 平方(決定係數)。

此外,通過確保模型隨著時間的推移產生一致的結果來評估模型的穩定性也至關重要。

穩定擴散模型最佳實踐

為了確保穩定擴散模型的成功訓練,請考慮以下最佳實踐:

  • 使用準確、最新且具有代表性的數據進行培訓。
  • 使用不同的數據集測試模型以評估其性能。
  • 在評估過程中評估模型的準確性和穩定性。
  • 為模型選擇適當的算法、架構和參數。
  • 通過應用數據預處理技術來提高模型的準確性。
  • 並通過持續監控變更或更新來確保其持續性能。

擴散模型應用

擴散模型在各個行業都有廣泛的應用,包括金融、醫療保健、營銷和遊戲。穩定擴散模型的一些常見用途是:

  • 電子商務:網站可以使用穩定的擴散模型根據文字描述生成產品圖像,從而無需真實照片即可展示產品。
  • 廣告:廣告公司可以利用穩定的擴散模型為其廣告活動生成獨特且具有視覺吸引力的視覺效果。
  • 遊戲:遊戲開發者可以採用穩定的擴散模型,根據文本描述生成遊戲資產,例如角色和環境。

訓練穩定擴散需要多長時間?

訓練穩定擴散所需的時間取決於許多因素。因此包括數據集的大小、您使用的硬件以及輸出圖像的質量。

如果您使用較小的數據集或功能較弱的硬件,則訓練穩定擴散將需要更長的時間。例如,一位用戶報告說,他們花了大約 2 週的時間在單個 V100 GPU 上訓練穩定擴散。

如果您不確定訓練穩定擴散需要多長時間,您可以先嘗試使用較小的數據集或功能較弱的硬件。您還可以嘗試使用預先訓練的穩定擴散模型,這將為您節省一些時間。

以下是一些加快穩定擴散訓練的技巧:

  • 使用更大的數據集:更大的數據集將為穩定擴散提供更多可供學習的信息,這將加快訓練過程。
  • 使用更強大的GPU:更強大的GPU將能夠更快地處理數據,這也將加快訓練過程。
  • 使用預先訓練的模型:預先訓練的模型已經具有一些如何生成圖像的知識,這將加快訓練過程。

常見問題 (FAQ)

問:如何製作穩定擴散模型?

答:製作穩定擴散模型需要大量的技術知識和資源。這不是一件容易或快速就能完成的事情。以下是製作穩定擴散模型的基本步驟:

  • 收集大量圖像數據集:該數據集應盡可能多樣化,以確保模型可以生成各種圖像。
  • 預處理數據集:這涉及將圖像轉換為模型可以理解的格式。
  • 訓練模型:這是最耗時的步驟。該模型需要在數據集上進行長時間的訓練,才能學習如何生成圖像。
  • 測試模型:模型訓練完成後,需要在新的圖像數據集上進行測試。這將有助於確保模型生成高質量的圖像。

問:訓練穩定擴散模型需要多長時間?

答:訓練穩定擴散模型所需的時間取決於多種因素,包括數據集的大小、模型的複雜性和可用的計算資源。

一般來說,在大型數據集上訓練穩定擴散模型可能需要幾天甚至幾週的時間。例如,在 ImageNet 數據集上訓練穩定擴散模型在單個 GPU 上可能需要長達 10 天的時間。

如果您使用較小的數據集或不太複雜的模型,訓練時間會更短。然而,值得注意的是,即使是小模型也可能需要幾個小時來訓練。

問:如何通過穩定擴散獲得更好的結果?

答:您可以採取一些措施來獲得更好的穩定擴散效果:

  • 使用更大的數據集:模型需要學習的數據越多,結果就越好。
  • 使用更複雜的模型:更複雜的模型將能夠學習數據中更複雜的模式,從而獲得更好的結果。
  • 訓練模型的時間越長:模型訓練的時間越長,結果就越好。
  • 使用更好的優化器:優化器是一種幫助模型學習的數學算法。使用更好的優化器可以幫助模型更快收斂並獲得更好的結果。
  • 使用更複雜的損失函數:損失函數是一個數學方程,用於衡量模型的性能。使用更複雜的損失函數可以幫助模型更有效地學習。
  • 使用正則化技術:正則化是一種有助於防止模型過度擬合數據的技術。當模型學習數據中的噪聲而不是底層模式時,就會發生過度擬合。使用正則化技術有助於提高模型的泛化性能。

問:如何訓練穩定擴散權重?

用戶可以使用多種方法訓練穩定擴散權重,包括:

  • 監督學習:在監督學習中,模型在已標記有所需輸出的圖像數據集上進行訓練。例如,該模型可以使用貓和狗的圖像數據集,每個圖像標記為“貓”或“狗”。
  • 無監督學習:在無監督學習中,模型在沒有任何標籤的圖像數據集上進行訓練。該模型學習在數據中查找模式,而無需明確告知要查找什麼。
  • 半監督學習:在半監督學習中,模型在已部分標記的圖像數據集上進行訓練。當沒有足夠的標記數據可用時,這可能是提高模型性能的有用方法。

訓練穩定擴散權重的最佳方法取決於具體應用。例如,如果你想訓練一個模型來生成貓和狗的圖像,監督學習將是一個不錯的選擇。如果你想訓練一個模型來生成任何物體的圖像,無監督學習將是更好的選擇。

問:穩定擴散可以訓練嗎?

答:是的,穩定擴散是可以訓練的。它是一種擴散模型,是一類可以訓練生成圖像的生成模型。穩定擴散是一種特殊類型的擴散模型,其設計比其他擴散模型更穩定且更易於訓練。

穩定擴散模型使用稱為對抗訓練的技術進行訓練。在對抗性訓練中,兩個模型相互訓練。一種模型是生成器,它負責生成圖像。另一個模型是鑑別器,負責區分真實圖像和生成圖像。

生成器可以生成盡可能真實的圖像。鑑別器可以區分真實圖像和生成圖像。作為生成器和鑑別器,它們在各自的任務上變得更好。最終,生成器變得非常擅長生成逼真的圖像,以至於鑑別器無法再區分它們。

問:訓練穩定擴散需要多少張照片?

答:訓練穩定擴散所需的照片數量取決於要訓練的模型的大小和復雜性。較大的模型比較小的模型需要更多的照片。

一般來說,您至少需要幾千張照片來訓練穩定擴散模型。但是,如果使用稱為數據增強的技術,則可以使用更少的照片來訓練模型。數據增強是一種通過從現有圖像創建新圖像來人為地增加數據集大小的技術。

結論

訓練穩定的擴散模型似乎具有挑戰性。然而,理解這個過程並使用正確的方法可以將其變成結果預測的強大工具。

本綜合指南的步驟和最佳實踐可以幫助您掌握這些模型的訓練並充分發揮其潛力。

無論您是業餘愛好者還是專業人士,深入研究穩定擴散模型的令人興奮的世界都可以讓您創造出令人驚嘆的視覺效果並獲得寶貴的見解。

Ubuntu 16.04 升级OPENSSL

Ubuntu 16.04 系统默认带的是1.0.2的openssl,而openssl暴露的漏洞越来越多,而ubuntu似乎也不打算在升级包中包含它,只能手动升级它了。

首先下载最新的openssl源码包

wget https://www.openssl.org/source/openssl-1.1.1k.tar.gz
tar xvfz openssl-1.1.1k.tar.gz

cd openssl-1.1.1k/

./config
make
make test
make install

创建openssl软链接

mv /usr/bin/openssl /root/
ln -s /usr/local/ssl/bin/openssl /usr/bin/openssl

链接加密缺失的so文件

ln -s /usr/local/lib/libssl.so.1.1 /usr/lib/
ln -s /usr/local/lib/libcrypto.so.1.1 /usr/lib/

来试试看效果
openssl version
OpenSSL 1.1.1k  25 Mar 2021

以太坊入门(三)用web3j进行以太转账及代币转账

上章讲到账户的查询,本章讲述账户转账。

  1. 以太坊转账 We3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Credentials credentials = WalletTool.loadCredentials(fromAddress); EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); RawTransaction rawTransaction = RawTransaction.createEtherTransaction( nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(), Convert.toWei("45000", Convert.Unit.WEI).toBigInteger(), toAddress, new BigInteger(amount)); byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signedMessage); EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).sendAsync().get(); if (ethSendTransaction.hasError()) { log.info("transfer error:", ethSendTransaction.getError().getMessage()); } else { String transactionHash = ethSendTransaction.getTransactionHash(); log.info("Transfer transactionHash:" + transactionHash); }
  2. 以太坊代币转账 Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Credentials credentials = WalletTool.loadCredentials(fromAddress); EthGetTransactionCount ethGetTransactionCount = web3j.ethGetTransactionCount( fromAddress, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger nonce = ethGetTransactionCount.getTransactionCount(); Function function = new Function( "transfer", Arrays.asList(new Address(toAddress), new Uint256(new BigInteger(amount))), Arrays.asList(new TypeReference<Type>() { })); String encodedFunction = FunctionEncoder.encode(function); RawTransaction rawTransaction = RawTransaction.createTransaction(nonce, Convert.toWei("18", Convert.Unit.GWEI).toBigInteger(), Convert.toWei("100000", Convert.Unit.WEI).toBigInteger(), contractAddress, encodedFunction); byte[] signedMessage = TransactionEncoder.signMessage(rawTransaction, credentials); String hexValue = Numeric.toHexString(signedMessage); log.debug("transfer hexValue:" + hexValue); EthSendTransaction ethSendTransaction = web3.ethSendRawTransaction(hexValue).sendAsync().get(); if (ethSendTransaction.hasError()) { log.info("transfer error:", ethSendTransaction.getError().getMessage()); } else { String transactionHash = ethSendTransaction.getTransactionHash(); log.info("Transfer transactionHash:" + transactionHash); }

代币转账和以太转账的区别在于,to地址是合约地址,而input是有三部分数据构成:transfer方法的哈希+收款人的地址+转账金额。此处比较难理解的正是Function部分,设置好参数以后,调用rawTransaction就可以了。

本站始发,转载于 https://www.jianshu.com/p/8ae984e6bafc

以太坊入门(二)用web3j进行以太查询及通证查询

以太坊的开发,基本都是go语言和nodejs的天下,web3j出现给java开发人员提供了很大的便利。本文会对一些以太坊的基本操作用java语言来实现。

本章会讲述通过web3j进行账户余额的查询。

  1. 以太余额查询
    以太的余额查询比较简单,直接调用web3j的ethGetBalance就可以。 Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); EthGetBalance ethGetBalance = web3j.ethGetBalance( address, DefaultBlockParameterName.LATEST).sendAsync().get(); BigInteger balance = ethGetBalance.getBalance();
  2. 通证的余额查询
    代币的查询就比较复杂一些,研究了好长时间,最后发现每个代币合约都会实现balanceOf方法,可以通过这个方法来查询通证的余额。 Web3j web3j = Web3j.build(new HttpService(ConstantLibs.WEB3_ADDRESS)); Function function = new Function( "balanceOf", Arrays.asList(new Address(address)), // Solidity Types in smart contract functions Arrays.asList(new TypeReference<Type>() { })); String encodedFunction = FunctionEncoder.encode(function); org.web3j.protocol.core.methods.response.EthCall response = web3j.ethCall( org.web3j.protocol.core.methods.request.Transaction.createEthCallTransaction(address, contract, encodedFunction), DefaultBlockParameterName.LATEST) .sendAsync().get(); String returnValue = response.getValue(); //返回16进制余额 returnValue = returnValue.substring(2); BigInteger balance = new BigInteger(returnValue, 16);

本站始发,转载于https://www.jianshu.com/p/0f3e65622d65

以太坊入门(一)账户和nonce的关系

什么是nonce?

在以太坊的交易数据中,大家都可以看到一个数字,nonce,从0开始,一直向上递增,这个代表什么意思呢?

以太坊所有的交易都是基于account的,不同于基于utxo的比特币,因此需要对每次交易都按顺序记录,nonce值就是这个顺序,主要用来防止重放攻击。

发起一笔交易,nonce就会加一。对于发起的解释:

1.外部账户每发送一笔交易;

2.合约账户每创建一个合约

而转入交易、合约调用其他合约等属于内部调用,因此nonce值不变。

如何使用nonce

发起转账或者创建合约的时候,通过web3从以太坊网络查询当前的nonce(ethGetTransactionCount)值,使用此值作为当前交易的nonce值,发送到以太坊网络即可。

nonce使用的几条规则

1. 当nonce太小(小于当前的nonce值),交易会被直接拒绝,Transactions with too low a nonce get immediately rejected;

2. 当nonce太大,大于当前nonce,交易会一直处于队列之中,Transactions with too high a nonce get placed in the transaction pool queue;

3.当发送一个比较大的nonce值,然后补齐开始nonce到那个值之间的nonce,那么交易依旧可以被执行,If transactions with nonces that fill the gap between the last valid nonce and the too high nonce are sent and the nonce sequence is complete, all the transactions in the sequence will get processed and mined.

4. 交易队列只保存最多64个从同一个账户发出的交易,The transaction pool queue will only hold a maximum of 64 transactions with the same From:address with nonces out of sequence. 也就是说,如果要批量转账,同一节点不要发出超过64笔交易。

5.当某节点queue中还有交易,但此时停止geth客户端,queue中的交易会被清除掉,When the geth instances are shut down and restarted, transactions in the transaction pool queue disappear.

6.当前nonce合适,但是账户余额不足时,会被以太坊拒绝;

7.如果发起一笔交易,但是因为gwei比较低或者网络比较忙的时候,该交易还没矿工挖出,可以通过使用相同的nonce和较高的gas费用,从而“覆盖”前一笔交易;

树莓派充当airplay接收器

iOS升级以后,新版本经常不兼容xbian之类自带的airplay功能,目前来Shairport的支持还是不错的。我在新的树梅派3b+上编译了一下,支持ios 11.0.4版本。

首先升级树莓派

sudo apt-get update
sudo apt-get upgrade

然后安装依赖包

sudo apt-get install autoconf automake avahi-daemon build-essential git libasound2-dev libavahi-client-dev libconfig-dev libdaemon-dev libpopt-dev libssl-dev libtool xmltoman

下载shairport源码

git clone https://github.com/mikebrady/shairport-sync.git

生成配置文件

cd shairport-sync
autoreconf -i -f
./configure --with-alsa --with-avahi --with-ssl=openssl --with-systemd --with-metadata

编译安装

make
sudo make install

设置为自动启动

sudo systemctl enable shairport-sync

启动

sudo service shairport-sync start

然后就可以在手机里面找到airplay设备,raspberrypi了。

Nginx反向代理跨域option问题解决

CORS on Nginx

The following Nginx configuration enables CORS, with support for preflight requests.

#
# Wide-open CORS config for nginx
#
location / {
     if ($request_method = 'OPTIONS') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        #
        # Custom headers and headers various browsers *should* be OK with but aren't
        #
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        #
        # Tell client that this pre-flight info is valid for 20 days
        #
        add_header 'Access-Control-Max-Age' 1728000;
        add_header 'Content-Type' 'text/plain; charset=utf-8';
        add_header 'Content-Length' 0;
        return 204;
     }
     if ($request_method = 'POST') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
     if ($request_method = 'GET') {
        add_header 'Access-Control-Allow-Origin' '*';
        add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
        add_header 'Access-Control-Allow-Headers' 'DNT,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Range';
        add_header 'Access-Control-Expose-Headers' 'Content-Length,Content-Range';
     }
}

First is tricking Nginx that a 405 status is actually a 200 OK and then proxy_pass it to your HAProxy like this:

error_page 405 =200 @405;
location @405 {
    root /;
    proxy_pass http://yourproxy:8080;
}

The second solution is just to catch the OPTIONS request and build a response for those requests:

location / {
    if ($request_method = OPTIONS ) {
        add_header Content-Length 0;
        add_header Content-Type text/plain;
        return 200;
    }
}

CentOS 7 下 firewalld的基本操作

这两天服务器升级,升级后发现有些服务不能用了。后来研究了一下,是因为防火墙的原因。之前调试,为了偷懒,把防火墙关了,就没启动过,现在想想裸奔了几个月,心真是大。

对外增加服务:

firewall-cmd --zone=public --add-port=80/tcp --permanent

对内设置安全区

firewall-cmd –permanent –zone=internal –change-interface=enp03s

firewall-cmd --zone=public --add-port=3306/tcp --permanent

最后,再重新加载firwalld策略

firewall-cmd --reload

以下转载:

http://qianxunclub.com/linux-centos-7-fang-huo-qiang-zhi-ju-you-ming-ling-xing-de-firewalldde-ji-ben-cao-zuo/

启动FirewallD服务:

?

1
2
systemctl enable firewalld.service #设置开机启动
systemctl start firewalld.service #开启服务

查看防火墙状态:

?

1
systemctl status firewalld

1. 区域管理

1.1. 网络区域简介

通过将网络划分成不同的区域,制定出不同区域之间的访问控制策略来控制不同程序区域间传送的数据流。例如,互联网是不可信任的区域,而内部网络是高度信任的区域。网络安全模型可以在安装,初次启动和首次建立网络连接时选择初始化。该模型描述了主机所连接的整个网络环境的可信级别,并定义了新连接的处理方式。有如下几种不同的初始化区域:

  • 阻塞区域(block):任何传入的网络数据包都将被阻止。
  • 工作区域(work):相信网络上的其他计算机,不会损害你的计算机。
  • 家庭区域(home):相信网络上的其他计算机,不会损害你的计算机。
  • 公共区域(public):不相信网络上的任何计算机,只有选择接受传入的网络连接。
  • 隔离区域(DMZ):隔离区域也称为非军事区域,内外网络之间增加的一层网络,起到缓冲作用。对于隔离区域,只有选择接受传入的网络连接。
  • 信任区域(trusted):所有的网络连接都可以接受。
  • 丢弃区域(drop):任何传入的网络连接都被拒绝。
  • 内部区域(internal):信任网络上的其他计算机,不会损害你的计算机。只有选择接受传入的网络连接。
  • 外部区域(external):不相信网络上的其他计算机,不会损害你的计算机。只有选择接受传入的网络连接。

注:FirewallD的默认区域是public。

1.2. 显示支持的区域列表

?

1
firewall-cmd --get-zones

1.3. 设置为家庭区域

?

1
firewall-cmd --set-default-zone=home

1.4. 查看当前区域

?

1
firewall-cmd --get-active-zones

1.5. 设置当前区域的接口

?

1
firewall-cmd --get-zone-of-interface=enp03s

1.6. 显示所有公共区域(public)

?

1
firewall-cmd --zone=public --list-all

1.7. 临时修改网络接口(enp0s3)为内部区域(internal)

?

1
firewall-cmd --zone=internal --change-interface=enp03s

1.8. 永久修改网络接口enp03s为内部区域(internal)

?

1
firewall-cmd --permanent --zone=internal --change-interface=enp03s

2. 服务管理

2.1. 显示服务列表

Amanda, FTP, Samba和TFTP等最重要的服务已经被FirewallD提供相应的服务,可以使用如下命令查看:

?

1
firewall-cmd --get-services

2.2. 允许SSH服务通过

?

1
firewall-cmd --enable service=ssh

2.3. 禁止SSH服务通过

?

1
firewall-cmd --disable service=ssh

2.4. 打开TCP的8080端口

?

1
firewall-cmd --enable ports=8080/tcp

2.5. 临时允许Samba服务通过600秒

?

1
firewall-cmd --enable service=samba --timeout=600

2.6. 显示当前服务

?

1
firewall-cmd --list-services

2.7. 添加HTTP服务到内部区域(internal)

?

1
2
firewall-cmd --permanent --zone=internal --add-service=http
firewall-cmd --reload #在不改变状态的条件下重新加载防火墙

3. 端口管理

3.1. 打开端口

?

1
2
#打开443/TCP端口
firewall-cmd --add-port=443/tcp

?

1
2
3
4
5
#永久打开3690/TCP端口
firewall-cmd --permanent --add-port=3690/tcp
#永久打开端口好像需要reload一下,临时打开好像不用,如果用了reload临时打开的端口就失效了
#其它服务也可能是这样的,这个没有测试
firewall-cmd --reload

?

1
2
#查看防火墙,添加的端口也可以看到
firewall-cmd --list-all

4. 直接模式

FirewallD包括一种直接模式,使用它可以完成一些工作,例如打开TCP协议的9999端口

?

1
2
firewall-cmd --direct -add-rule ipv4 filter INPUT 0 -p tcp --dport 9000 -j ACCEPT
firewall-cmd --reload

5. 关闭服务的方法

你也可以关闭目前还不熟悉的FirewallD防火墙,而使用iptables,命令如下:

?

1
2
3
4
5
systemctl stop firewalld
systemctl disable firewalld
yum install iptables-services
systemctl start iptables
systemctl enable iptables

Auto start a java Swing GUI program when raspberry boots

I planed make an self-desgin photo or movie player base on Raspberry. Also I can use it as photo frame. If I need improve the performance of the PI, I need write it with Python, I think.

 

Part 1 – Build the Foundation

In this part, we will focus on preparing Raspbian Lite.

1. Download the latest Raspbian Lite image.
2. Format the SD / microSD card with Raspbian Lite (Plenty of guides out there on how to do this. For macOS, Linux, and Windows users, Etcher is an easy to use application that can help you do this.)
3. Insert the SD / microSD card into the Pi.
4. Connect the Pi to the Internet using an Ethernet cable. If you want to use Wi-Fi instead, you will have to read on how to configure your wireless receiver using the command line after your Pi has finished booting.
5. Connect your TV / Monitor and keyboard. (Mouse is optional at this time.) Turn on the Pi. The Pi should boot up successfully and a prompt to log in will appear.
6. Log into Raspbian. The username is pi and the password is raspberry.

 

7. We will install Xorg. To do this type in:

sudo apt-get install –no-install-recommends xserver-xorg

sudo apt-get install –no-install-recommends xinit

now, you can write you java program now. For example, I wrote a test program with a button in the center of screen. once I click the button, the window will change to the full size of the screen.

import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;

public class FullScreenTest {
public static void main(String[] args) {
final JFrame f = new JFrame(“FullScreenTest”);
final JButton btn = new JButton(“FullScreen”);
btn.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
if (btn.getText().equals(“FullScreen”)) {
f.dispose();
f.setUndecorated(true);
f.getGraphicsConfiguration().getDevice().setFullScreenWindow(f);
f.setVisible(true);
btn.setText(“NormalMode”);
} else {
f.dispose();
f.setUndecorated(false);
f.getGraphicsConfiguration().getDevice().setFullScreenWindow(null);
f.setVisible(true);
btn.setText(“FullScreen”);
}
}
});

f.getContentPane().setLayout(new FlowLayout());
f.getContentPane().add(btn);
f.pack();
f.setLocationRelativeTo(null);
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setVisible(true);
}
}

 

Pack the file into a jar file like GUI.jar.

In order to have a command or program run when the Pi boots, you can add commands to the rc.local file. This is especially useful if you want to be able to plug your Pi in to power headless, and have it run a program without configuration or a manual start.

EDITING RC.LOCAL

On your Pi, edit the file /etc/rc.local using the editor of your choice. You must edit with root, for example:

sudo nano /etc/rc.local

Add commands below the comment, but leave the line exit 0 at the end, then save the file and exit.

sudo xinit /usr/local/jdk1.8.0_77/bin/java -jar /usr/local/mypi/GUI.jar — :1 &

 

 

Reboot your PI, then done!

解决PKIX问题:unable to find valid certification path to requested target

话说前几天在测试服务器上遇到了这么个异常

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

就是说找不着安全证书啥的等等烂码七糟的一大堆

接着就拜Google大神,发现一篇文章能被N个人转来转去的,关键文章还不怎么靠谱

后来找到了一个办法,幸运的是在测试环境一弄, 这个问题看上去就被解决了

我们要做的就是将所要访问的URL的安全认证证书导入到客户端

下面是获取安全证书的一种方法

/*
 * Copyright 2006 Sun Microsystems, Inc.  All Rights Reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 *   - Redistributions of source code must retain the above copyright
 *     notice, this list of conditions and the following disclaimer.
 *
 *   - Redistributions in binary form must reproduce the above copyright
 *     notice, this list of conditions and the following disclaimer in the
 *     documentation and/or other materials provided with the distribution.
 *
 *   - Neither the name of Sun Microsystems nor the names of its
 *     contributors may be used to endorse or promote products derived
 *     from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
 * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
 * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.security.KeyStore;
import java.security.MessageDigest;
import java.security.cert.CertificateException;
import java.security.cert.X509Certificate;

import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLException;
import javax.net.ssl.SSLSocket;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;

public class InstallCert {
	public static void main(String[] args) throws Exception {
		String host;
		int port;
		char[] passphrase;
		if ((args.length == 1) || (args.length == 2)) {
			String[] c = args[0].split(":");
			host = c[0];
			port = (c.length == 1) ? 443 : Integer.parseInt(c[1]);
			String p = (args.length == 1) ? "changeit" : args[1];
			passphrase = p.toCharArray();
		} else {
			System.out.println("Usage: java InstallCert <host>[:port] [passphrase]");
			return;
		}

		File file = new File("jssecacerts");
		if (file.isFile() == false) {
			char SEP = File.separatorChar;
			File dir = new File(System.getProperty("java.home") + SEP + "lib" + SEP + "security");
			file = new File(dir, "jssecacerts");
			if (file.isFile() == false) {
				file = new File(dir, "cacerts");
			}
		}
		
		System.out.println("Loading KeyStore " + file + "...");
		InputStream in = new FileInputStream(file);
		KeyStore ks = KeyStore.getInstance(KeyStore.getDefaultType());
		ks.load(in, passphrase);
		in.close();

		SSLContext context = SSLContext.getInstance("TLS");
		TrustManagerFactory tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm());
		tmf.init(ks);
		X509TrustManager defaultTrustManager = (X509TrustManager) tmf.getTrustManagers()[0];
		SavingTrustManager tm = new SavingTrustManager(defaultTrustManager);
		context.init(null, new TrustManager[]{tm}, null);
		SSLSocketFactory factory = context.getSocketFactory();

		System.out.println("Opening connection to " + host + ":" + port + "...");
		SSLSocket socket = (SSLSocket) factory.createSocket(host, port);
		socket.setSoTimeout(10000);
		try {
			System.out.println("Starting SSL handshake...");
			socket.startHandshake();
			socket.close();
			System.out.println();
			System.out.println("No errors, certificate is already trusted");
		} catch (SSLException e) {
			System.out.println();
			e.printStackTrace(System.out);
		}

		X509Certificate[] chain = tm.chain;
		if (chain == null) {
			System.out.println("Could not obtain server certificate chain");
			return;
		}

		BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));

		System.out.println();
		System.out.println("Server sent " + chain.length + " certificate(s):");
		System.out.println();
		MessageDigest sha1 = MessageDigest.getInstance("SHA1");
		MessageDigest md5 = MessageDigest.getInstance("MD5");
		for (int i = 0; i < chain.length; i++) {
			X509Certificate cert = chain[i];
			System.out.println(" " + (i + 1) + " Subject " + cert.getSubjectDN());
			System.out.println("   Issuer  " + cert.getIssuerDN());
			sha1.update(cert.getEncoded());
			System.out.println("   sha1    " + toHexString(sha1.digest()));
			md5.update(cert.getEncoded());
			System.out.println("   md5     " + toHexString(md5.digest()));
			System.out.println();
		}

		System.out.println("Enter certificate to add to trusted keystore or 'q' to quit: [1]");
		String line = reader.readLine().trim();
		int k;
		try {
			k = (line.length() == 0) ? 0 : Integer.parseInt(line) - 1;
		} catch (NumberFormatException e) {
			System.out.println("KeyStore not changed");
			return;
		}

		X509Certificate cert = chain[k];
		String alias = host + "-" + (k + 1);
		ks.setCertificateEntry(alias, cert);

		OutputStream out = new FileOutputStream("jssecacerts");
		ks.store(out, passphrase);
		out.close();

		System.out.println();
		System.out.println(cert);
		System.out.println();
		System.out.println("Added certificate to keystore 'jssecacerts' using alias '" + alias + "'");
	}

	
	private static final char[] HEXDIGITS = "0123456789abcdef".toCharArray();

	
	private static String toHexString(byte[] bytes) {
		StringBuilder sb = new StringBuilder(bytes.length * 3);
		for (int b : bytes) {
			b &= 0xff;
			sb.append(HEXDIGITS[b >> 4]);
			sb.append(HEXDIGITS[b & 15]);
			sb.append(' ');
		}
		return sb.toString();
	}

	
	private static class SavingTrustManager implements X509TrustManager {
		private final X509TrustManager tm;
		private X509Certificate[] chain;

		SavingTrustManager(X509TrustManager tm) {
			this.tm = tm;
		}

		public X509Certificate[] getAcceptedIssuers() {
			throw new UnsupportedOperationException();
		}

		public void checkClientTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			throw new UnsupportedOperationException();
		}

		public void checkServerTrusted(X509Certificate[] chain, String authType) throws CertificateException {
			this.chain = chain;
			tm.checkServerTrusted(chain, authType);
		}
	}
}

编译InstallCert.java得到两个class文件,并执行InstallCert类

执行方式:java InstallCert hostname     eg:java InstallCert www.cebbank.com

接下来会看到下面的打印信息

java InstallCert www.cebbank.com
Loading KeyStore /usr/java/jdk1.6.0_31/jre/lib/security/cacerts...
Opening connection to www.cebbank.com:443...
Starting SSL handshake...

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at com.sun.net.ssl.internal.ssl.Alerts.getSSLException(Alerts.java:174)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.fatal(SSLSocketImpl.java:1731)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:241)
	at com.sun.net.ssl.internal.ssl.Handshaker.fatalSE(Handshaker.java:235)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1206)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.processMessage(ClientHandshaker.java:136)
	at com.sun.net.ssl.internal.ssl.Handshaker.processLoop(Handshaker.java:593)
	at com.sun.net.ssl.internal.ssl.Handshaker.process_record(Handshaker.java:529)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.readRecord(SSLSocketImpl.java:925)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.performInitialHandshake(SSLSocketImpl.java:1170)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1197)
	at com.sun.net.ssl.internal.ssl.SSLSocketImpl.startHandshake(SSLSocketImpl.java:1181)
	at InstallCert.main(InstallCert.java:102)
Caused by: sun.security.validator.ValidatorException: PKIX path building failed: 
sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:323)
	at sun.security.validator.PKIXValidator.engineValidate(PKIXValidator.java:217)
	at sun.security.validator.Validator.validate(Validator.java:218)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.validate(X509TrustManagerImpl.java:126)
	at com.sun.net.ssl.internal.ssl.X509TrustManagerImpl.checkServerTrusted(X509TrustManagerImpl.java:209)
	at InstallCert$SavingTrustManager.checkServerTrusted(InstallCert.java:198)
	at com.sun.net.ssl.internal.ssl.ClientHandshaker.serverCertificate(ClientHandshaker.java:1198)
	... 8 more
Caused by: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
	at sun.security.provider.certpath.SunCertPathBuilder.engineBuild(SunCertPathBuilder.java:174)
	at java.security.cert.CertPathBuilder.build(CertPathBuilder.java:238)
	at sun.security.validator.PKIXValidator.doBuild(PKIXValidator.java:318)
	... 14 more

Server sent 1 certificate(s):

 1 Subject CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing
   Issuer  CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network
   sha1    5b d2 85 6e b3 a4 2b 07 a2 13 47 b3 be 3e 1f c9 d3 ce 46 57 
   md5     05 d8 ae ee f1 d9 51 63 6d 2f 11 e0 ac d0 e7 d7 

Enter certificate to add to trusted keystore or 'q' to quit: [1]

然后输入 1 并回车,会看到类似下面的打印信息

[
[
  Version: V3
  Subject: CN=www.cebbank.com, OU=Terms of use at www.verisign.com/rpa (c)05, OU=CEB, O="China Everbright Bank Co., Ltd", L=Beijing
  Signature Algorithm: SHA1withRSA, OID = 1.2.840.113549.1.1.5

  Key:  Sun RSA public key, 2048 bits
  modulus: 30831246384548809540705228292841393062583732250993909916355780413722161557074568469738254573472093341710481517139910877
  public exponent: 65537
  Validity: [From: Mon Jul 02 08:00:00 CST 2012,
               To: Thu Jul 03 07:59:59 CST 2014]
  Issuer: CN=VeriSign Class 3 Extended Validation SSL CA, OU=Terms of use at https://www.verisign.com/rpa (c)06, OU=VeriSign Trust Network
  SerialNumber: [    5715ab25 6be8fa42 2fa28dd4 601bc732]

Certificate Extensions: 9
[1]: ObjectId: 1.3.6.1.5.5.7.1.1 Criticality=false
AuthorityInfoAccess [
  [
   accessMethod: 1.3.6.1.5.5.7.48.1
   accessLocation: URIName: http://ocsp.verisign.com, 
   accessMethod: 1.3.6.1.5.5.7.48.2
   accessLocation: URIName: http://EVSecure-aia.verisign.com/EVSecure2006.cer]
]

[2]: ObjectId: 2.5.29.17 Criticality=false
SubjectAlternativeName [
  DNSName: www.cebbank.com
]

[3]: ObjectId: 2.5.29.35 Criticality=false
AuthorityKeyIdentifier [
KeyIdentifier [
0000: FC 8A 50 BA 9E B9 25 5A   7B 55 85 4F 95 00 63 8F  ..P...%Z.U.O..c.
0010: E9 58 6B 43                                        .XkC
]

]

[4]: ObjectId: 2.5.29.32 Criticality=false
CertificatePolicies [
  [CertificatePolicyId: [2.16.840.1.113733.1.7.23.6]
[PolicyQualifierInfo: [
  qualifierID: 1.3.6.1.5.5.7.2.1
  qualifier: 0000: 16 1C 68 74 74 70 73 3A   2F 2F 77 77 77 2E 76 65  ..https://www.ve
0010: 72 69 73 69 67 6E 2E 63   6F 6D 2F 63 70 73        risign.com/cps

]]  ]
]

[5]: ObjectId: 2.5.29.19 Criticality=false
BasicConstraints:[
  CA:false
  PathLen: undefined
]

[6]: ObjectId: 1.3.6.1.5.5.7.1.12 Criticality=false
Extension unknown: DER encoded OCTET string =
0000: 04 62 30 60 A1 5E A0 5C   30 5A 30 58 30 56 16 09  .b0`.^.\0Z0X0V..
0010: 69 6D 61 67 65 2F 67 69   66 30 21 30 1F 30 07 06  image/gif0!0.0..
0020: 05 2B 0E 03 02 1A 04 14   4B 6B B9 28 96 06 0C BB  .+......Kk.(....
0030: D0 52 38 9B 29 AC 4B 07   8B 21 05 18 30 26 16 24  .R8.).K..!..0&.$
0040: 68 74 74 70 3A 2F 2F 6C   6F 67 6F 2E 76 65 72 69  http://logo.veri
0050: 73 69 67 6E 2E 63 6F 6D   2F 76 73 6C 6F 67 6F 31  sign.com/vslogo1
0060: 2E 67 69 66                                        .gif


[7]: ObjectId: 2.5.29.37 Criticality=false
ExtendedKeyUsages [
  serverAuth
  clientAuth
]

[8]: ObjectId: 2.5.29.31 Criticality=false
CRLDistributionPoints [
  [DistributionPoint:
     [URIName: http://EVSecure-crl.verisign.com/EVSecure2006.crl]
]]

[9]: ObjectId: 2.5.29.15 Criticality=false
KeyUsage [
  DigitalSignature
  Key_Encipherment
]

]
  Algorithm: [SHA1withRSA]
  Signature:
0000: 42 0A 89 BF 48 08 1E F4   98 F2 E5 DB 0D 83 EF 37  B...H..........7
0010: EC 27 6F 4D 81 69 C6 4A   4C 17 EC 57 F5 48 2A 14  .'oM.i.JL..W.H*.
0020: 3C 54 B2 C5 49 39 42 BA   EC 83 78 02 F9 96 6C 63  <T..I9B...x...lc
0030: 80 BC 60 61 BB 20 D1 AD   C3 D3 76 47 6F 0C 7B AC  ..`a. ....vGo...
0040: 76 B2 C7 2D B1 0A 7A 00   CA 40 38 86 FF 9F 12 F5  v..-..z..@8.....
0050: BE 5A E7 42 97 2F DF DE   0C 19 C5 F6 92 58 17 7A  .Z.B./.......X.z
0060: 9A 1D 2C 2C DA 8B 83 83   2D BE 07 58 56 36 92 E7  ..,,....-..XV6..
0070: B1 F8 A0 B5 00 F4 C3 30   D1 34 37 3D 94 75 28 04  .......0.47=.u(.
0080: A2 D8 C3 FE B1 E1 C2 2E   51 A8 6F D5 09 6D 49 DB  ........Q.o..mI.
0090: 2E 1D 4B F7 A8 06 30 B4   97 E7 C2 33 26 FD 6A DF  ..K...0....3&.j.
00A0: D6 B0 10 A1 F2 73 DD 5A   60 DE 51 5E EA 80 46 86  .....s.Z`.Q^..F.
00B0: 25 0B 53 FC C2 57 80 35   09 2D 31 55 28 35 EE 0F  %.S..W.5.-1U(5..
00C0: 62 50 4B 12 75 0B 02 9F   2F 0B D2 8A 0D 23 E3 C1  bPK.u.../....#..
00D0: 48 28 56 33 E1 DE 31 DD   72 78 15 96 EE 2B A5 1D  H(V3..1.rx...+..
00E0: 37 85 1B E5 88 53 80 88   02 6D 90 F3 E6 4A 74 AC  7....S...m...Jt.
00F0: D2 CA 0E 04 BC 46 A0 57   34 FA CF 9D E5 D7 0E 4B  .....F.W4......K

]

Added certificate to keystore 'jssecacerts' using alias 'www.cebbank.com-1'

同时我们会在当面目录下发现已经生成了一个名为jssecacerts的证书

再将名为jssecacerts的证书拷贝\\%JAVA_HONME%\\jre\\lib\\security\\目录中

最后重启下应用的服务,证书就会生效了。。

补充: 有人说生成证书后不用拷贝,直接代码里加句话就行,结果试了一下发现不管用

System.setProperty("javax.net.ssl.trustStore", "jssecacerts证书路径");

[转]openssl的证书格式转换

证书转换

PKCS 全称是 Public-Key Cryptography Standards ,是由 RSA 实验室与其它安全系统开发商为促进公钥密码的发展而制订的一系列标准,PKCS 目前共发布过 15 个标准。 常用的有:
PKCS#7 Cryptographic Message Syntax Standard
PKCS#10 Certification Request Standard
PKCS#12 Personal Information Exchange Syntax Standard
X.509是常见通用的证书格式。所有的证书都符合为Public Key Infrastructure (PKI) 制定的 ITU-T X509 国际标准。
PKCS#7 常用的后缀是: .P7B .P7C .SPC
PKCS#12 常用的后缀有: .P12 .PFX
X.509 DER 编码(ASCII)的后缀是: .DER .CER .CRT
X.509 PAM 编码(Base64)的后缀是: .PEM .CER .CRT
.cer/.crt是用于存放证书,它是2进制形式存放的,不含私钥。
.pem跟crt/cer的区别是它以Ascii来表示。
pfx/p12用于存放个人证书/私钥,他通常包含保护密码,2进制方式
p10是证书请求
p7r是CA对证书请求的回复,只用于导入
p7b以树状展示证书链(certificate chain),同时也支持单个证书,不含私钥。

1. CA证书

用openssl创建CA证书的RSA密钥(PEM格式):

openssl genrsa -des3 -out ca.key 1024

2. 创建CA证书有效期为一年

用openssl创建CA证书(PEM格式,假如有效期为一年):

openssl req -new -x509 -days 365 -key ca.key -out ca.crt -config openssl.cnf

openssl是可以生成DER格式的CA证书的,最好用IE将PEM格式的CA证书转换成DER格式的CA证书。

3. x509转换为pfx

openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt

4. PEM格式的ca.key转换为Microsoft可以识别的pvk格式

pvk -in ca.key -out ca.pvk -nocrypt -topvk

5. PKCS#12 到 PEM 的转换

openssl pkcs12 -nocerts -nodes -in cert.p12 -out private.pem  验证   openssl pkcs12 -clcerts -nokeys -in cert.p12 -out cert.pem

6. 从 PFX 格式文件中提取私钥格式文件 (.key)

openssl pkcs12 -in mycert.pfx -nocerts -nodes -out mycert.key

7. 转换 pem 到到 spc

   openssl crl2pkcs7 -nocrl -certfile venus.pem  -outform DER -out venus.spc

用 -outform -inform 指定 DER 还是 PAM 格式。例如:

openssl x509 -in Cert.pem -inform PEM -out cert.der -outform DER

8. PEM 到 PKCS#12 的转换

openssl pkcs12 -export -in Cert.pem -out Cert.p12 -inkey key.pem

IIS 证书

cd c:\openssl            set OPENSSL_CONF=openssl.cnf            openssl pkcs12 -export -out server.pfx -inkey server.key -in server.crt

server.key和server.crt文件是Apache的证书文件,生成的server.pfx用于导入IIS

9. How to Convert PFX Certificate to PEM Format for SOAP

$ openssl pkcs12 -in test.pfx -out client.pem  Enter Import Password:  MAC verified OK  Enter PEM pass phrase:  Verifying - Enter PEM pass phrase:

FTP时显示500 Illegal PORT command的解决

使用EditPlus打开FTP服务器上的文件时,发现连接不了

在windows的dos窗口用FTP命令去连时,可以登录,但使用ls等命令时,出现:
500 Illegal PORT command.
425 Use PORT or PASV first.
根据提示是被动模式的问题

在EditPlus的FTP设定高级选项中,选上passive FTP mode即可而dos窗口的FTP命令则无法设置为被动模式

FTP主/被动模式的原理
————————————————————————————————————————————————–
FTP是File Transfer Protocol(文件传输协议)的缩写,用来在两台计算机之间互相传送文件相比于HTTP,FTP协议要复杂得多复杂的原因,是因为FTP协议要用到两个TCP连接,一个是命令链路,用来在FTP客户端与服务器之间传递命令;另一个是数据链路,用来上传或下载数据

FTP协议有两种工作方式:PORT方式和PASV方式,中文意思为主动式和被动式

PORT(主动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路当需要传送数据时,客户端在命令链路上用PORT命令告诉服务器:我打开了XXXX端口,你过来连接我于是服务器从20端口向客户端的XXXX端口发送连接请求,建立一条数据链路来传送数据

PASV(被动)方式的连接过程是:客户端向服务器的FTP端口(默认是21)发送连接请求,服务器接受连接,建立一条命令链路当需要传送数据时,服务器在命令链路上用PASV命令告诉客户端:我打开了XXXX端口,你过来连接我于是客户端向服务器的XXXX端口发送连接请求,建立一条数据链路来传送数据
概括:
——————————————————————————–
主动模式:服务器向客户端敲门,然后客户端开门
被动模式:客户端向服务器敲门,然后服务器开门

所以,如果你是如果通过代理上网的话,就不能用主动模式,因为服务器敲的是上网代理服务器的门,而不是敲客户端的门
而且有时候,客户端也不是轻易就开门的,因为有防火墙阻挡,除非客户端开放大于1024的高端端口

——————————————————————————–
要用主动模式来下载,请您把下载工具的被动模式(PASV)都不要打勾,用主动模式来下载就OK了,如果在出错,那就被动主动相互转换一下

常见的FTP客户端软件的PASV方式的关闭方法

大部分FTP客户端默认使用PASV方式,PASV模式的意式是被动模式 在大部分FTP客户端的设置里,常见到的字眼都是PASV或被动模式

IE: 工具 -> Internet选项 -> 高级 -> 使用被动FTP(需要IE6.0以上才支持)

CuteFTP: Edit -> Setting -> Connection -> Firewall -> PASV Mode
或 File -> Site Manager,在左边选中站点 -> Edit -> Use PASV mode

FlashGet: 工具 -> 选项 -> 代理服务器 -> 直接连接 -> 编辑 -> PASV模式

FlashFXP: 选项 -> 参数选择 -> 代理/防火墙/标识 -> 使用被动模式
或 站点管理 -> 对应站点 -> 选项 -> 使用被动模式
或 快速连接 -> 切换 -> 使用被动模式

LeapFTP: Option ->Preferences -> General->Proxy->Use Pasv Mode